zorba-coders team mailing list archive
-
zorba-coders team
-
Mailing list archive
-
Message #23166
[Merge] lp:~zorba-coders/zorba/http-module into lp:zorba
Federico Cavalieri has proposed merging lp:~zorba-coders/zorba/http-module into lp:zorba.
Requested reviews:
Cezar Andrei (cezar-andrei)
For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/http-module/+merge/169579
JSON HTTP Client Module
--
https://code.launchpad.net/~zorba-coders/zorba/http-module/+merge/169579
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'modules/CMakeLists.txt'
--- modules/CMakeLists.txt 2013-02-07 17:24:36 +0000
+++ modules/CMakeLists.txt 2013-06-15 00:58:33 +0000
@@ -17,6 +17,7 @@
ADD_SUBDIRECTORY(functx)
ADD_SUBDIRECTORY(xqxq)
ADD_SUBDIRECTORY(w3c)
+ADD_SUBDIRECTORY(io)
# Add external module projects - any subdirectories of a directory
# named "zorba_modules" as a sibling to the main Zorba source
=== added directory 'modules/io'
=== added file 'modules/io/CMakeLists.txt'
--- modules/io/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ modules/io/CMakeLists.txt 2013-06-15 00:58:33 +0000
@@ -0,0 +1,14 @@
+# Copyright 2006-2013 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+ADD_SUBDIRECTORY(zorba)
=== added directory 'modules/io/zorba'
=== added file 'modules/io/zorba/CMakeLists.txt'
--- modules/io/zorba/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/CMakeLists.txt 2013-06-15 00:58:33 +0000
@@ -0,0 +1,14 @@
+# Copyright 2006-2013 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+ADD_SUBDIRECTORY(modules)
=== added directory 'modules/io/zorba/modules'
=== added file 'modules/io/zorba/modules/CMakeLists.txt'
--- modules/io/zorba/modules/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/CMakeLists.txt 2013-06-15 00:58:33 +0000
@@ -0,0 +1,58 @@
+# Copyright 2006-2013 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+#
+# cURL
+#
+SET (CURL_FOUND)
+IF(ZORBA_SUPPRESS_CURL)
+ MESSAGE(STATUS "ZORBA_SUPPRESS_CURL is true - not searching for cURL library")
+ELSE(ZORBA_SUPPRESS_CURL)
+ MESSAGE(STATUS "Looking for cURL")
+ FIND_PACKAGE(CURL)
+
+ IF(CURL_FOUND)
+ MESSAGE(STATUS "Found cURL library -- " ${CURL_LIBRARIES})
+ INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
+ #DECLARE_ZORBA_MODULE(FILE http-client-error.xq
+ #URI "http://expath.org/ns/error";)
+ DECLARE_ZORBA_MODULE(FILE http-client.xq VERSION 1.0
+ URI "http://zorba.io/modules/http-client";
+ LINK_LIBRARIES ${CURL_LIBRARIES})
+
+ IF (WIN32) # Copy certificates for windows only
+ IF (MSVC_IDE)
+ SET(CACERT_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../../../../../bin/${CMAKE_BUILD_TYPE}/cacert.pem")
+ ELSE (MSVC_IDE)
+ SET(CACERT_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../../../../../bin/cacert.pem")
+ ENDIF (MSVC_IDE)
+ CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cacert.pem" ${CACERT_DESTINATION} COPYONLY)
+ INSTALL(FILES ${CACERT_DESTINATION} DESTINATION bin)
+ ENDIF (WIN32)
+
+ ELSE(CURL_FOUND)
+ MESSAGE(STATUS "The cURL library was not found - http-client will not be built")
+ ENDIF(CURL_FOUND)
+ENDIF(ZORBA_SUPPRESS_CURL)
+SET(ZORBA_HAVE_CURL ${CURL_FOUND} CACHE BOOL "Whether Zorba found cURL" FORCE)
+MARK_AS_ADVANCED(ZORBA_HAVE_CURL)
+
+# error and warning modules
+#DECLARE_ZORBA_MODULE (FILE pregenerated/errors.xq
+ #URI "http://www.zorba-xquery.com/errors";
+#)
+#DECLARE_ZORBA_MODULE (FILE pregenerated/warnings.xq
+ #URI "http://www.zorba-xquery.com/warnings";
+#)
=== added file 'modules/io/zorba/modules/http-client.jsound'
--- modules/io/zorba/modules/http-client.jsound 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.jsound 2013-06-15 00:58:33 +0000
@@ -0,0 +1,215 @@
+{
+ "$namespace": "http://zorba.io/modules/http-client";,
+ "$about": "This JSound schema defines the types of requests and
+ responses used in the http://28.io/http-client module",
+ "$types": [
+ {
+ "$kind": "object",
+ "$name": "headers",
+ "$about": "This type represents a set of headers. Each header is represented
+ by a different name-value pair.",
+ "$constraints" : "every $key in keys($$) satisfies $$.$key instance of string"
+
+ },
+ {
+ "$kind": "object",
+ "$name": "body",
+ "$about": "This type represents the body of an HTTP request or an HTTP
+ response. In multi-part requests and responses, it represents the
+ body of a single part.",
+ "$content": {
+ "media-type": {
+ "$type": "string",
+ "$about": "This field is the media type of the body."
+ },
+ "src": {
+ "$type": "anyURI",
+ "$about": "This field, used only in HTTP requests, is used to specify the URL at
+ which the request can be found. It is mutually exclusive with the content
+ field.",
+ "$optional": true
+ },
+ "content": {
+ "$type": "string",
+ "$about": "The HTTP request or response body. It is mutually exclusive with the src
+ field.",
+ "$optional": true
+ }
+ },
+ "$constraints" : "count($$.src) + count($$.content) le 1"
+ },
+ {
+ "$kind": "object",
+ "$name": "part",
+ "$about": "This type represents each single part of a multipart HTTP request or
+ response.",
+ "$content": {
+ "headers": {
+ "$type": "headers",
+ "$optional": true,
+ "$about": "This field specifies the part headers."
+ },
+ "body": {"$type": "body"}
+ }
+ },
+ {
+ "$kind": "object",
+ "$name": "multipart",
+ "$about": "This type represents a multipart HTTP request or response.",
+ "$content": {
+ "media-type": {
+ "$type": "string"
+ "$about": "The media-type attribute is the media type of the request or
+ response, and has to be a multipart media type (that is, its
+ main type must be multipart)."
+ },
+ "boundary": {
+ "$type": "string",
+ "$optional": true,
+ "$about": "The boundary attribute is the boundary marker used to separate
+ the several parts in the message (the value of the attribute is
+ prefixed with "--" to form the actual boundary marker in the
+ request; on the other way, this prefix is removed from the boundary
+ marker in the response to set the value of the attribute."
+ },
+ "parts": {
+ "$kind": "array",
+ "$content": ["part"],
+ "$about": "The parts of the multipart request.",
+ "$optional": true
+ }
+ }
+ },
+ {
+ "$kind": "object",
+ "$name": "options",
+ "$about": "This type represents an HTTP request options.",
+ "$content": {
+ "status-only": {
+ "$type": "boolean",
+ "$optional": true,
+ "$about": "Controls how the response will look like; if true, only the status code
+ and the headers are returned, the content is not."
+ },
+ "override-media-type": {
+ "$type": "string",
+ "$about": "Is a MIME type that will override the Content-Type header returned
+ by the server.",
+ "$optional": true
+ },
+ "follow-redirect": {
+ "$type": "boolean",
+ "$optional": true,
+ "$about": "Control whether an http redirect is automatically followed or not. If
+ it is false, the http redirect is returned as the response. If it is
+ true (the default) the function tries to follow the redirect, by
+ sending the same request to the new address (including body, headers,
+ and authentication credentials.) Maximum one redirect is followed
+ (there is no attempt to follow a redirect in response to following a
+ first redirect.)"
+ },
+ "timeout": {
+ "$type": "integer",
+ "$optional": true,
+ "$about": "Is the maximum number of seconds to wait for the server to respond. If
+ this time duration is reached, an error is thrown."
+ },
+ "user-agent": {
+ "$type": "string",
+ "$optional": true,
+ "$about": "The user agent sent to the server when issuing the request."
+ },
+ }
+ },
+ {
+ "$kind": "object",
+ "$name": "authentication",
+ "$about": "This type represents an HTTP authentication.",
+ "$content": {
+ "username": {
+ "$type": "string",
+ "$about": "The authentication username."
+ },
+ "password": {
+ "$type": "string",
+ "$about": "The authentication password."
+ },
+ "auth-method": {
+ "$type": "string",
+ "$about": "The authentication method."
+ }
+ }
+ },
+ {
+ "$kind": "object",
+ "$name": "request",
+ "$content": {
+ "method": {
+ "$type": "string",
+ "$about: "Is the http verb to use, as GET, POST, etc. It is case insensitive."
+ },
+ "href": {
+ "$type": "anyURI",
+ "$about": "Is the URI the request has to be sent to. It can be overridden by the
+ parameter $href."
+ },
+ "authentication": {
+ "$type": "authentication",
+ "$optional": true,
+ "$about": "Specifies the HTTP authentication when sending the request."
+ },
+ "options": {
+ "$type": "options",
+ "$optional": true,
+ "$about": "Specifies the HTTP request options."
+ },
+ "headers": {
+ "$type": "headers",
+ "$optional": true,
+ "$about": "Specifies the HTTP request headers."
+ },
+ "body": {
+ "$type": "body",
+ "$optional": true,
+ "$about": "Specifies the body of a non-multipart HTTP request."
+ },
+ "multipart": {
+ "$type": "multipart",
+ "$optional": true,
+ "$about": "Specifies a multipart HTTP request."
+ }
+ },
+ "$constraints" : "count($$.body) + count($$.multipart) le 1"
+ },
+ {
+ "$kind": "object",
+ "$name": "response",
+ "$content": {
+ "status": {
+ "$type": "integer",
+ "$about": "This is the HTTP status code returned by the server."
+ },
+ "message": {
+ "$type": "string",
+ "$about": "This is the message returned by the server on the status line."
+ },
+ "headers": {
+ "$type": "headers",
+ "$optional": true,
+ "$about": "The reponse headers returned by the server."
+ },
+ "body": {
+ "$type": "body",
+ "$optional": true,
+ "$about": "The body of a non-multipart HTTP response."
+ },
+ "multipart": {
+ "$type": "multipart",
+ "$optional": true,
+ "$about": "Specifies a multipart HTTP response."
+ }
+ },
+ "$constraints" : "count($$.body) + count($$.multipart) le 1"
+ }
+ ]
+}
\ No newline at end of file
=== added file 'modules/io/zorba/modules/http-client.xq'
--- modules/io/zorba/modules/http-client.xq 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,698 @@
+jsoniq version "1.0";
+
+(:
+ : Copyright 2006-2013 The FLWOR Foundation.
+ :
+ : Licensed under the Apache License, Version 2.0 (the "License");
+ : you may not use this file except in compliance with the License.
+ : You may obtain a copy of the License at
+ :
+ : http://www.apache.org/licenses/LICENSE-2.0
+ :
+ : Unless required by applicable law or agreed to in writing, software
+ : distributed under the License is distributed on an "AS IS" BASIS,
+ : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ : See the License for the specific language governing permissions and
+ : limitations under the License.
+ :)
+
+
+(:~
+ : <p>
+ : This module provides functions for performing HTTP requests.
+ : </p>
+ :
+ : <h2>A simple GET request using the get#1 convenience function</h2>
+ :
+ : <pre>
+ : import module namespace http="http://www.zorba.io/modules/http-client";;
+ : http:get("http://www.example.com";)
+ : </pre>
+ :
+ : <p>
+ : This example makes a GET request to example.com and returns the server's response
+ : as a JSON object.
+ : </p>
+ :
+ : <pre>
+ : {
+ : "status" : 200,
+ : "message" : "OK",
+ : "headers" : {
+ : "Content-Length" : "1270",
+ : "Date" : "Tue, 11 Jun 2013 22:27:10 GMT",
+ : ...
+ : },
+ : "body" : {
+ : "media-type" : "text/html",
+ : "content" : "..."
+ : }
+ : }
+ : </pre>
+ :
+ : <h2 id="standard_return">Response format</h2>
+ :
+ : <p>Most functions in this module (all except <a href="#options-1">options#1</a>)
+ : return a single JSON item, describing the server's response, as in the previous
+ : example.
+ : The server status (integer) and message (string) fields are always present.
+ : If the server replied sending one or more headers, they are reported
+ : in an optional headers object. Each header is represented as a single (string)
+ : field.</p>
+ :
+ : <p>For non-multipart responses, as in the previous example, the response body,
+ : if any, is reported as a body object. This object contains both the (string)
+ : media-type returned by the server and its content.
+ : The type of the content field is determined by the media-type returned by the
+ : server. If the media-type indicates that the body content is textual,
+ : then the content has type string, base64Binary otherwise.
+ : Specifically, the body content is considered textual only if the MIME-type specified in
+ : the media-type is one of:
+ : <ul>
+ : <li>"application/json"</li>
+ : <li>"application/x-javascript"</li>
+ : <li>"application/xml"</li>
+ : <li>"application/xml-external-parsed-entity"</li>
+ : </ul>
+ : or if the MIME-type starts with "text/" or ends with "+xml".</p>
+ :
+ : <p>For multipart responses, multiple bodies are returned, as in the following example: </p>
+ :
+ : <pre>
+ : {
+ : "status" : 200,
+ : "message" : "OK",
+ : "headers" : {
+ : "Date" : "Tue, 11 Jun 2013 22:34:13 GMT",
+ : ...
+ : },
+ : "multipart" : {
+ : "boundary": "--AaB03x",
+ : "parts": [
+ : {
+ : "headers" : {
+ : "Content Disposition: file",
+ : ...
+ : },
+ : "body": {
+ : "media-type" : "image/gif",
+ : "content" : "..."
+ : }
+ : },
+ : {
+ : "body" : {
+ : "media-type" : "text/html",
+ : "content" : "..."
+ : }
+ : }
+ : ]
+ : }
+ : </pre>
+ :
+ : <p>The multipart field contains both the boundary used to separate parts
+ : and an array containing all parts. Each part contains its specific headers,
+ : if any, and the corresponding body.</p>
+ :
+ : <h2 id="nondeterministic_warning">Important Notice Regarding Nondeterministic Functions</h2>
+ :
+ : <p>
+ : The following functions in this module -
+ : <a href="#get-1">get#1</a>,
+ : <a href="#get-text-1">get-text#1</a>,
+ : <a href="#get-binary-1">get-binary#1</a>,
+ : <a href="#send-nondeterministic-request-1">send-nondeterministic-request-1</a>,
+ : <a href="#head-1">head#1</a>, and
+ : <a href="#options-1">options#1</a>
+ : are declared to be <i>nondeterministic</i>, which means that their results
+ : will not be cached.
+ : However, they are <b>not</b> declared to be
+ : <i>sequential</i>, which means that they may be re-ordered during query optimization.
+ : According to the HTTP RFC, GET, HEAD an OPTIONS requests should not have any side-effects.
+ : However, in practice it is not uncommon, especially for GET requests, to have side-effects.
+ : If your application depends on the ordering of side-effects from requests issued through
+ : these functions, you should either use the <a href="#send-request-3">send-request()</a>
+ : function (which is declared <i>sequential</i>), or alternatively
+ : wrap each call to get() in your own sequential function, to ensure
+ : that the requests are not reordered.
+ : </p>
+ :
+ : <h1 id="url_string">$href Arguments to Functions</h1>
+ :
+ : <p>Several functions in this module accept a URL argument named $href. In
+ : all cases, the value passed to $href must be a valid xs:anyURI.
+ : However, all functions declare $href to be of type xs:string. This
+ : is for convenience, since you can pass a string literal value (that
+ : is, a URL in double-quotes spelled out explicitly in your query)
+ : to an xs:string parameter.</p>
+ :
+ : <h1 id="expath_relation">Relation to the EXPath http-client module</h1>
+ :
+ : <p><a href="http://expath.org/";>EXPath</a> defines its own http-client
+ : module, which is available separately.
+ : There are two primary differences between EXPath's http-client and
+ : this module:
+ :
+ : <ol>
+ : <li>EXPath defines only the send-request() function, although it
+ : does include convenient 1- and 2-argument forms in addition to the
+ : full 3-argument form. EXPath does not include the simpler get(),
+ : post(), put(), delete(), head(), and options() functions defined by
+ : this module.</li>
+ : <li>EXPath uses XML to represent request for its send-request() function,
+ : whereas this module uses JSON.</li>
+ : <li>EXPath specifies that all XML content returned by an HTTP server
+ : will be parsed and returned as an XML document, whereas all HTML content
+ : will be <i>tidied up</i> into valid XML, and then parsed into an element.
+ : This module returns any textual content as string and any binary content
+ : as base6Binary.</li>
+ : <li>EXPath accepts XML nodes as body in the send-request() function and
+ : automatically serializes them into a string. The send-request() function
+ : defined in this module only allows string and base64Binary as body types.
+ : </li>
+ : </ol>
+ : </p>
+ :
+ : <p>
+ : See <a href="http://www.expath.org/spec/http-client";>the full spec
+ : of the EXPath http-client module</a> for more information.
+ : </p>
+ :
+ : @author Federico Cavalieri, Markus Pilman
+ : @see <a href="http://www.w3.org/TR/xquery-11/#FunctionDeclns";>XQuery 1.1: Function Declaration</a>
+ : @library <a href="http://curl.haxx.se/";>cURL Library</a>
+ : @project external
+ :)
+module namespace http = "http://zorba.io/modules/http-client";;
+
+import module namespace libjn = "http://jsoniq.org/function-library";;
+
+declare namespace an = "http://www.zorba-xquery.com/annotations";;
+declare namespace ver = "http://www.zorba-xquery.com/options/versioning";;
+declare namespace err = "http://www.w3.org/2005/xqt-errors";;
+
+declare option ver:module-version "1.0";
+
+(:~
+ : <p>
+ : This function sends an HTTP request and returns the corresponding response.
+ : </p>
+ :
+ : <p>
+ : This function is declared as sequential and should be used whenever the
+ : request may have side-effects.
+ : </p>
+ :
+ : <p>
+ : The request parameters are specified in the $request JSON object, which
+ : has the following minimal structure:
+ :
+ : <pre>
+ : {
+ : "href": "http://www.example.com";
+ : }
+ : </pre>
+ : </p>
+ :
+ : <p>This object specifies a GET request of the URI "http://www.example.com";</p>
+ :
+ : <p>Additional optional parameters can be specified when issuing a request,
+ : using the following structure:</p>
+ : <pre>
+ : {
+ : "method": "POST",
+ : "href": "http://www.example.com";,
+ : "authentication":
+ : {
+ : "username" : "user",
+ : "password" : "pass",
+ : "auth-method" : "Basic"
+ : },
+ : "options":
+ : {
+ : "status-only": true,
+ : "override-media-type": "text/plain",
+ : "follow-redirect": false,
+ : "timeout": 30,
+ : "user-agent": "Mozilla/5.0"
+ : },
+ : "headers":
+ : {
+ : "name": "value",
+ : ...
+ : },
+ : "body":
+ : {
+ : "media-type": "text/plain",
+ : "content": "..."
+ : }
+ : }
+ :</pre>
+ : <p>
+ : The method field (string) defines the HTTP verb to use in the HTTP request (i.e., GET, HEAD, OPTIONS,
+ : POST, PUT, DELETE). If not specified GET will be used.
+ : The authentication field can be used to specify the credentials and authentication method
+ : used when issuing a request (e.g, Basic). If the authentication field is specified, all its (string)
+ : subfields must be specified. If an authentication object is provided, it overrides any
+ : Authorization header specified in the request.
+ : Additionally, the following options can be specified:
+ : <ul>
+ : <li>status-only. If true, the response body contents are omitted from the response object.</li>
+ : <li>override-media-type. Is a MIME type that will override the Content-Type header returned
+ : by the server. It affects the type of the result body content.</li>
+ : <li>follow-redirect. Control whether an http redirect is automatically followed or not. If
+ : it is false, the http redirect is returned as the response. If it is
+ : true (the default) the function tries to follow the redirect, by
+ : sending the same request to the new address (including body, headers,
+ : and authentication credentials.) Maximum one redirect is followed
+ : (there is no attempt to follow a redirect in response to following a
+ : first redirect).</li>
+ : <li>timeout. Is the maximum number of seconds to wait for the server to respond.
+ : If no response is received withing this time duration, an error is thrown.</li>
+ : <li>user-agent. The user agent sent to the server when issuing the request.
+ : If not specified libcurl-agent/1.0 is used.</li>
+ : </ul>
+ : </p>
+ :
+ : <p>One or more headers can be sent to the server, specifying them in an optional headers object.
+ : Each header is represented as a single (string) field. These headers are overridden if the corresponding
+ : option/authentication has been specified in the request.</p>
+ :
+ : <p>For non-multipart request a body object can be specified.
+ : This object must contain both the desired (string) media-type and its content.
+ : The type of the content field must be either string or base64Binary. </p>
+ :
+ : <p>For multipart requests, multipart object can be specified in place of the body object.
+ : The multipart object has the following structure: </p>
+ :
+ : <pre>
+ : "multipart" : {
+ : "boundary": "--AaB03x",
+ : "parts": [
+ : {
+ : "headers" : {
+ : "Content Disposition: file",
+ : ...
+ : },
+ : "body": {
+ : "media-type" : "image/gif",
+ : "content" : "..."
+ : }
+ : },
+ : {
+ : "body" : {
+ : "media-type" : "text/html",
+ : "content" : "..."
+ : }
+ : }
+ : ]
+ : }
+ : </pre>
+ :
+ : <p>The multipart field contains an optional (string) field which specifies
+ : the boundary used to separate each part and an array containing all parts.
+ : Each part contains its specific headers, if any, and the corresponding body.
+ : </p>
+ :
+ :
+ : @param $request a JSON http-client request object
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC004 The src attribute on the body element is mutually exclusive with all other
+ : attributes (except media-type).
+ : @error http:HC005 The specified request object is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ : @error http:HCV02 Trying to follow a redirect of a POST, PUT, or DELETE request.
+ : @error http:HCV03 The specified charset is unsupported.
+ : @error http:HCV04 The type of the request body must be string or xs:base64Binary.
+ :
+ :)
+declare %an:sequential function http:send-request($request as object) as object
+{
+ if (http:check-request($request))
+ then http:http-sequential-impl($request)
+ else ()
+};
+
+(:~
+ : <p>
+ : This function sends an HTTP request and returns the corresponding response.
+ : </p>
+ : <p>
+ : This function has the same semantics of <a href="#send-request-1">send-request-1</a>,
+ : but is declared as nondeterministic and thus should only be used when
+ : the request has no side-effects.
+ : </p>
+ :
+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
+ : @param $request see request parameter of <a href="#send-request-1">send-request#1</a>
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC004 The src attribute on the body element is mutually exclusive with all other
+ : attributes (except media-type).
+ : @error http:HC005 The specified request object is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ : @error http:HCV02 Trying to follow a redirect of a POST, PUT, or DELETE request.
+ : @error http:HCV03 The specified charset is unsupported.
+ : @error http:HCV04 The type of the request body must be string or xs:base64Binary.
+ :)
+declare %an:nondeterministic function http:send-nondeterministic-request($request as object) as object
+{
+ if (http:check-request($request))
+ then http:http-nondeterministic-impl($request)
+ else ()
+};
+
+
+(:~
+ : <p>
+ : This function makes a GET request to a given URL.
+ : </p>
+ :
+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
+ : @param $href The URL to which the request will be made (see
+ : <a href="#url_string">note</a> above).
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC005 The specified href is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ :)
+declare %an:nondeterministic function http:get($href as string) as object
+{
+ http:send-nondeterministic-request(
+ {
+ "method" : "GET",
+ "href": $href
+ })
+};
+
+(:~
+ : <p>
+ : This function makes a GET request to a given URL. All returned bodies
+ : are forced to be interpreted as textual, with a UTF-8 charset and will
+ : be returned as string items.
+ : </p>
+ :
+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
+ : @param $href The URL to which the request will be made (see
+ : <a href="#url_string">note</a> above).
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC005 The specified href is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ :
+ :)
+declare %an:nondeterministic function http:get-text($href as string) as object
+{
+ http:send-nondeterministic-request(
+ {
+ "method": "GET",
+ "href": $href,
+ "options": {
+ "override-media-type": "text/plain; charset=utf-8"
+ }
+ })
+};
+
+(:~
+ : <p>
+ : This function makes a GET request on a given URL. All returned bodies
+ : are forced to be interpreted as binary data, and will be returned
+ : as base64Binary items.
+ : </p>
+ :
+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
+ : @param $href The URL to which the request will be made (see
+ : <a href="#url_string">note</a> above).
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC005 The specified href is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ :
+ :)
+declare %an:nondeterministic function http:get-binary($href as string) as object
+{
+ http:send-nondeterministic-request(
+ {
+ "method": "GET",
+ "href": $href,
+ "options": {
+ "override-media-type": "binary"
+ }
+ })
+};
+
+(:~
+ : <p>
+ : This function makes an HTTP HEAD request on a given URL.
+ : </p>
+ :
+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
+ : @param $href The URL to which the request will be made (see
+ : <a href="#url_string">note</a> above).
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC005 The specified href is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ :
+ : @example test/rbkt/Queries/zorba/http-client/head/head_status.xq
+ :)
+declare %an:nondeterministic function http:head($href as string) as object
+{
+ http:send-nondeterministic-request(
+ {
+ "method": "HEAD",
+ "href": $href
+ })
+};
+
+(:~
+ : <p>
+ : This function makes an HTTP OPTIONS request, which asks the server
+ : which operations it supports.
+ : </p>
+ :
+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
+ : @param $href The URL to which the request will be made (see
+ : <a href="#url_string">note</a> above).
+ : @return A sequence of string values of the allowed operations.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC005 The specified href is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ :
+ : @example test/rbkt/Queries/zorba/http-client/options/options.xq
+ :)
+declare %an:nondeterministic function http:options($href as string) as string*
+{
+ let $resp := http:send-nondeterministic-request(
+ {
+ "method": "OPTIONS",
+ "href": $href
+ })[1]
+ return
+ fn:tokenize($resp.headers.Allow, ",")
+};
+
+
+(:~
+ : <p>
+ : This function makes an HTTP PUT request to a given URL.
+ : </p>
+ : <p>
+ : The body passed to this function must be either a string or a base64Binary.
+ : If it is a string, the Content-Type sent to the server will be "text/plain",
+ : "application/octet-stream" otherwise.
+ : </p>
+ :
+ : @param $href The URL to which the request will be made (see
+ : <a href="#url_string">note</a> above).
+ : @param $body The body which will be sent to the server.
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC005 The specified href is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ : @error http:HCV04 The type of the request body must be string or xs:base64Binary.
+ :
+ :)
+declare %an:sequential function http:put($href as string, $body as atomic) as object
+{
+ variable $media-type as xs:string :=
+ typeswitch($body)
+ case string return "text/plain"
+ case xs:base64Binary return "application/octet-stream"
+ default return fn:error(xs:QName("http:HCV04"), "The type of the request body must be string or xs:base64Binary.");
+ http:put($href, $body, $media-type)
+};
+
+(:~
+ : <p>
+ : This function makes an HTTP PUT request to a given URL.
+ : </p>
+ : <p>
+ : The body passed to this function must be either a string or a base64Binary.
+ : In any case, Content-Type of the request sent to the server will
+ : be $content-type.
+ : </p>
+ :
+ : @param $href The URL to which the request will be made (see
+ : <a href="#url_string">note</a> above).
+ : @param $body The body which will be sent to the server.
+ : @param $content-type The content type of $body to send to the server.
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC005 The specified request object is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ : @error http:HCV03 The specified charset is unsupported.
+ : @error http:HCV04 The type of the request body must be string or xs:base64Binary.
+ :
+ :)
+declare %an:sequential function http:put($href as string, $body as atomic, $content-type as string) as object
+{
+ http:send-request(
+ {
+ "method": "PUT",
+ "href": $href,
+ "body": {
+ "media-type": $content-type,
+ "content": $body
+ }
+ })
+};
+
+(:~
+ : <p>
+ : This function makes an HTTP DELETE request to a given URL.
+ : </p>
+ :
+ : @param $href The URL to which the request will be made (see
+ : <a href="#url_string">note</a> above).
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC005 The specified request is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ :
+ :)
+declare %an:sequential function http:delete($href as xs:string) as object
+{
+ http:send-request(
+ {
+ "method": "DELETE",
+ "href": $href
+ })
+};
+
+(:~
+ : <p>
+ : This function makes an HTTP POST request to a given URL.
+ : </p>
+ : <p>
+ : The body passed to this function must be either a string or a base64Binary.
+ : If it is a string, the Content-Type sent to the server will be "text/plain",
+ : "application/octet-stream" otherwise.
+ : </p>
+ :
+ : @param $href The URL to which the request will be made (see
+ : <a href="#url_string">note</a> above).
+ : @param $body The body which will be sent to the server.
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC005 The specified request is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ : @error http:HCV04 The type of the request body must be string or xs:base64Binary.
+ :
+ :)
+declare %an:sequential function http:post($href as string, $body as atomic) as object
+{
+ variable $media-type as xs:string :=
+ typeswitch($body)
+ case string return "text/plain"
+ case base64Binary return "application/octet-stream"
+ default return fn:error(xs:QName("http:HCV04"), "The type of the request body must be string or xs:base64Binary.");
+
+ http:post($href, $body, $media-type)
+};
+
+(:~
+ : <p>
+ : This function makes an HTTP POST request to a given URL.
+ : </p>
+ : <p>
+ : The body passed to this function must be either a string or a base64Binary.
+ : In any case, Content-Type of the request sent to the server will
+ : be $content-type.
+ : </p>
+ :
+ : @param $href The URL to which the request will be made (see
+ : <a href="#url_string">note</a> above).
+ : @param $body The body which will be sent to the server
+ : @param $content-type The content type of the body as described above.
+ : @return <a href="#standard_return">standard http-client return type</a>.
+ :
+ : @error http:HC001 An HTTP error occurred.
+ : @error http:HC005 The specified request is not valid.
+ : @error http:HC006 A timeout occurred waiting for the response.
+ : @error http:HCV03 The specified charset is unsupported.
+ : @error http:HCV04 The type of the request body must be string or xs:base64Binary.
+ :
+ :)
+declare %an:sequential function http:post($href as string, $body as atomic, $content-type as string) as object
+{
+ http:send-request(
+ {
+ "method": "POST",
+ "href": $href,
+ "body": {
+ "media-type": $content-type,
+ "content": $body
+ }
+ })
+};
+
+
+(:~
+ : Private function used internally by this module.
+ :
+ : This function checks if the request, href, and bodies parameters
+ : are consistent.
+ :
+ : @error http:HC004 The src attribute on the body element is mutually exclusive with all other attribute (except the media-type).
+ : @error http:HC005 The specified request object is not valid.
+ : @error http:HCV04 The type of the request body must be string or xs:base64Binary.
+ :)
+declare %private function http:check-request($request as object) as boolean
+{
+ for $body in libjn:descendant-objects($request).body
+ return
+ (
+ if (exists($body.src) and exists($body.content))
+ then fn:error(xs:QName("http:HC004"), "The src and content fields of a body are mutually exclusive.")
+ else (),
+ if (exists($body.content))
+ then
+ typeswitch($body.content)
+ case string return ()
+ case xs:base64Binary return ()
+ default return fn:error(xs:QName("http:HCV04"), "The type of the body content must be string or xs:base64Binary.")
+ else ()
+ ),
+ if (count(libjn:descendant-objects($request).body[exists($$.src) and exists($$.content)]) gt 1)
+ then fn:error(xs:QName("http:HC004"), "The src and content fields of a body are mutually exclusive.")
+ else if (exists($request.href) and not($request.href castable as xs:anyURI))
+ then fn:error(xs:QName("http:HC005"), "The specified href is not a valid anyURI.")
+ else (),
+ fn:true()
+};
+
+declare %private %an:sequential function http:http-sequential-impl($request as object) as object external;
+
+declare %private %an:nondeterministic function http:http-nondeterministic-impl($request as object) as object external;
=== added directory 'modules/io/zorba/modules/http-client.xq.src'
=== added file 'modules/io/zorba/modules/http-client.xq.src/curl_overwrite.h'
--- modules/io/zorba/modules/http-client.xq.src/curl_overwrite.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/curl_overwrite.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CURL_OVERWRITE_H
+#define CURL_OVERWRITE_H
+
+#include "curl_wrappers.h"
+#include "curl_redefines.h"
+
+#endif // CURL_OVERWRITE_H
=== added file 'modules/io/zorba/modules/http-client.xq.src/curl_redefines.h'
--- modules/io/zorba/modules/http-client.xq.src/curl_redefines.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/curl_redefines.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CURL_REDEFINES_H
+#define CURL_REDEFINES_H
+
+#define curl_easy_init() curl_easy_init_wrapped(__FILE__, __LINE__)
+#define curl_multi_init() curl_multi_init_wrapped(__FILE__, __LINE__)
+#define curl_easy_setopt(x, y, z) curl_easy_setopt_wrapped(__FILE__, __LINE__, x, y, z)
+//#define curl_multi_perform(x,y) curl_multi_perform_wrapped(__FILE__, __LINE__, x, y)
+//#define curl_multi_info_read(x,y) curl_multi_info_read_wrapped(__FILE__, __LINE__, x, y)
+#define curl_slist_free_all(x) curl_slist_free_all_wrapped(__FILE__, __LINE__, x)
+#define curl_formfree(x) curl_formfree_wrapped(__FILE__, __LINE__, x)
+#define curl_slist_append(x,y) curl_slist_append_wrapped(__FILE__, __LINE__, x, y)
+#define curl_multi_add_handle(x,y) curl_multi_add_handle_wrapped(__FILE__, __LINE__, x, y)
+
+#endif // CURL_REDEFINES_H
=== added file 'modules/io/zorba/modules/http-client.xq.src/curl_stream_buffer.cpp'
--- modules/io/zorba/modules/http-client.xq.src/curl_stream_buffer.cpp 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/curl_stream_buffer.cpp 2013-06-15 00:58:33 +0000
@@ -0,0 +1,379 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zorba/config.h>
+
+#include <cstdlib>
+#include <cstring> /* for memcpy(3) */
+#include <iostream>
+#include <cassert>
+#ifndef WIN32
+#include <cerrno>
+#include <sys/time.h>
+#endif /* WIN32 */
+
+#include <curl/multi.h>
+
+#include "curl_stream_buffer.h"
+#include "inform_data_read.h"
+
+using namespace std;
+
+namespace zorba {
+namespace curl {
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define ZORBA_CURL_ASSERT(expr) \
+ do { \
+ if ( CURLcode const code##__LINE__ = (expr) ) \
+ throw exception( #expr, "", code##__LINE__ ); \
+ } while (0)
+
+#define ZORBA_CURLM_ASSERT(expr) \
+ do { \
+ if ( CURLMcode const code##__LINE__ = (expr) ) \
+ if ( code##__LINE__ != CURLM_CALL_MULTI_PERFORM ) \
+ throw exception( #expr, "", code##__LINE__ ); \
+ } while (0)
+
+exception::exception( char const *function, char const *uri, char const *msg ) :
+ std::exception(), msg_( msg )
+{
+}
+
+exception::exception( char const *function, char const *uri, CURLcode code ) :
+ std::exception(),
+ msg_( curl_easy_strerror( code ) )
+{
+}
+
+exception::exception( char const *function, char const *uri, CURLMcode code ) :
+ std::exception(),
+ msg_( curl_multi_strerror( code ) )
+{
+}
+
+exception::~exception() throw() {
+ // out-of-line since it's virtual
+}
+
+const char* exception::what() const throw() {
+ return msg_.c_str();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CURL* create( char const *uri, write_fn_t fn, void *data ) {
+ //
+ // Having cURL initialization wrapped by a class and using a singleton static
+ // instance guarantees that cURL is initialized exactly once before use and
+ // and also is cleaned-up at program termination (when destructors for static
+ // objects are called).
+ //
+ struct curl_initializer {
+ curl_initializer() {
+ ZORBA_CURL_ASSERT( curl_global_init( CURL_GLOBAL_ALL ) );
+ }
+ ~curl_initializer() {
+ curl_global_cleanup();
+ }
+ };
+ static curl_initializer initializer;
+
+ CURL *const curl = curl_easy_init();
+ if ( !curl )
+ throw exception( "curl_easy_init()", uri, "" );
+
+ try {
+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_URL, uri ) );
+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEDATA, data ) );
+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, fn ) );
+
+ // Tells cURL to follow redirects. CURLOPT_MAXREDIRS is by default set to -1
+ // thus cURL will do an infinite number of redirects.
+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1 ) );
+
+#ifndef ZORBA_VERIFY_PEER_SSL_CERTIFICATE
+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 0 ) );
+ //
+ // CURLOPT_SSL_VERIFYHOST is left default, value 2, meaning verify that the
+ // Common Name or Subject Alternate Name field in the certificate matches
+ // the name of the server.
+ //
+ // Tested with https://www.npr.org/rss/rss.php?id=1001
+ // About using SSL certs in curl: http://curl.haxx.se/docs/sslcerts.html
+#else
+# ifdef WIN32
+ // set the root CA certificates file path
+ if ( GENV.g_curl_root_CA_certificates_path[0] )
+ ZORBA_CURL_ASSERT(
+ curl_easy_setopt(
+ curl, CURLOPT_CAINFO, GENV.g_curl_root_CA_certificates_path
+ )
+ );
+# endif /* WIN32 */
+#endif /* ZORBA_VERIFY_PEER_SSL_CERTIFICATE */
+
+ //
+ // Some servers don't like requests that are made without a user-agent
+ // field, so we provide one.
+ //
+ //ZORBA_CURL_ASSERT(
+ //curl_easy_setopt( curl, CURLOPT_USERAGENT, "libcurl-agent/1.0" )
+ //);
+
+ return curl;
+ }
+ catch ( ... ) {
+ destroy( curl );
+ throw;
+ }
+}
+
+void destroy( CURL *curl ) {
+ if ( curl ) {
+ curl_easy_reset( curl );
+ curl_easy_cleanup( curl );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+streambuf::streambuf() {
+ init();
+}
+
+streambuf::streambuf( char const *uri ) {
+ init();
+ open( uri );
+}
+
+streambuf::streambuf( CURL *curl ) {
+ init();
+ curl_ = curl;
+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEDATA, this ) );
+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, curl_write_callback ) );
+ init_curlm();
+}
+
+streambuf::~streambuf() {
+ free( buf_ );
+ close();
+#ifdef WIN32
+ closesocket( dummy_socket_ );
+#endif
+ // If we have been assigned memory ownership of theInformer, delete it now.
+ if ( theOwnInformer )
+ delete theInformer;
+}
+
+void streambuf::close() {
+ if ( curl_ ) {
+ if ( curlm_ ) {
+ curl_multi_remove_handle( curlm_, curl_ );
+ curl_multi_cleanup( curlm_ );
+ curlm_ = 0;
+ }
+ destroy( curl_ );
+ curl_ = 0;
+ }
+}
+
+void streambuf::curl_read() {
+ buf_len_ = 0;
+ while ( curl_running_ && !buf_len_ ) {
+ fd_set fd_read, fd_write, fd_except;
+ FD_ZERO( &fd_read );
+ FD_ZERO( &fd_write );
+ FD_ZERO( &fd_except );
+ int max_fd = -1;
+#ifdef WIN32
+ //
+ // Windows does not like a call to select where all arguments are 0, so we
+ // just add a dummy socket to make the call to select happy.
+ //
+ FD_SET( dummy_socket_, &fd_read );
+#endif /* WIN32 */
+ ZORBA_CURLM_ASSERT(
+ curl_multi_fdset( curlm_, &fd_read, &fd_write, &fd_except, &max_fd )
+ );
+
+ //
+ // Note that the fopen.c sample code is unnecessary at best or wrong at
+ // worst; see: http://curl.haxx.se/mail/lib-2011-05/0011.html
+ //
+ timeval timeout;
+ long curl_timeout_ms;
+ ZORBA_CURLM_ASSERT( curl_multi_timeout( curlm_, &curl_timeout_ms ) );
+ if ( curl_timeout_ms > 0 ) {
+ timeout.tv_sec = curl_timeout_ms / 1000;
+ timeout.tv_usec = curl_timeout_ms % 1000 * 1000;
+ } else {
+ //
+ // From curl_multi_timeout(3):
+ //
+ // Note: if libcurl returns a -1 timeout here, it just means that
+ // libcurl currently has no stored timeout value. You must not wait
+ // too long (more than a few seconds perhaps) before you call
+ // curl_multi_perform() again.
+ //
+ // So we just pick some not-too-long default.
+ //
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ }
+
+ switch ( select( max_fd + 1, &fd_read, &fd_write, &fd_except, &timeout ) ) {
+ case -1: // select error
+#ifdef WIN32
+ char err_buf[8];
+ sprintf( err_buf, "%d", WSAGetLastError() );
+ throw exception( "select()", "", err_buf );
+#else
+ throw exception( "select()", "", strerror( errno ) );
+#endif
+ case 0: // timeout
+ // no break;
+ default:
+ CURLMcode code;
+ do {
+ code = curl_multi_perform( curlm_, &curl_running_ );
+ } while ( code == CURLM_CALL_MULTI_PERFORM );
+ ZORBA_CURLM_ASSERT( code );
+ }
+ }
+ if ( theInformer )
+ theInformer->afterRead();
+}
+
+size_t streambuf::curl_write_callback( void *ptr, size_t size, size_t nmemb,
+ void *data ) {
+ size *= nmemb;
+ streambuf *const that = static_cast<streambuf*>( data );
+
+ if ( that->theInformer )
+ that->theInformer->beforeRead();
+
+ size_t const buf_free = that->buf_capacity_ - that->buf_len_;
+ if ( size > buf_free ) {
+ streamoff new_capacity = that->buf_capacity_ + size - buf_free;
+ if ( void *const new_buf =
+ realloc( that->buf_, static_cast<size_t>( new_capacity ) ) ) {
+ that->buf_ = static_cast<char*>( new_buf );
+ that->buf_capacity_ = new_capacity;
+ } else
+ throw exception( "realloc()", "" );
+ }
+ ::memcpy( that->buf_ + that->buf_len_, ptr, size );
+ that->buf_len_ += size;
+ return size;
+}
+
+void streambuf::init() {
+ buf_ = 0;
+ buf_capacity_ = 0;
+ buf_len_ = 0;
+ curl_ = 0;
+ curlm_ = 0;
+ curl_running_ = 0;
+ theInformer = 0;
+ theOwnInformer = false;
+#ifdef WIN32
+ dummy_socket_ = socket( AF_INET, SOCK_DGRAM, 0 );
+ if ( dummy_socket_ == CURL_SOCKET_BAD || dummy_socket_ == INVALID_SOCKET )
+ throw exception( "socket()", "" );
+#endif /* WIN32 */
+}
+
+void streambuf::init_curlm() {
+ //
+ // Lie about cURL running initially so the while-loop in curl_read() will run
+ // at least once.
+ //
+ curl_running_ = 1;
+
+ //
+ // Set the "get" pointer to the end (gptr() == egptr()) so a call to
+ // underflow() and initial data read will be triggered.
+ //
+ buf_len_ = buf_capacity_;
+ setg( buf_, buf_ + buf_len_, buf_ + buf_capacity_ );
+
+ //
+ // Clean-up has to be done here with try/catch (as opposed to relying on the
+ // destructor) because open() can be called from the constructor. If an
+ // exception is thrown, the constructor will not have completed, hence the
+ // object will not have been fully constructed; therefore the destructor will
+ // not be called.
+ //
+ try {
+ if ( !(curlm_ = curl_multi_init()) )
+ throw exception( "curl_multi_init()", "" );
+ try {
+ ZORBA_CURLM_ASSERT( curl_multi_add_handle( curlm_, curl_ ) );
+ }
+ catch ( ... ) {
+ curl_multi_cleanup( curlm_ );
+ curlm_ = 0;
+ throw;
+ }
+ }
+ catch ( ... ) {
+ destroy( curl_ );
+ curl_ = 0;
+ throw;
+ }
+}
+
+int streambuf::multi_perform() {
+ underflow();
+ CURLMsg *msg;
+ int msgInQueue;
+ int error = 0;
+ while ( (msg = curl_multi_info_read( curlm_, &msgInQueue )) ) {
+ if ( msg->msg == CURLMSG_DONE )
+ error = msg->data.result;
+ }
+ return error;
+}
+
+void streambuf::open( char const *uri ) {
+ curl_ = create( uri, curl_write_callback, this );
+
+ init_curlm();
+}
+
+streamsize streambuf::showmanyc() {
+ return egptr() - gptr();
+}
+
+streambuf::int_type streambuf::underflow() {
+ while ( true ) {
+ if ( gptr() < egptr() )
+ return traits_type::to_int_type( *gptr() );
+ curl_read();
+ if ( !buf_len_ )
+ return traits_type::eof();
+ setg( buf_, buf_, buf_ + buf_len_ );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace curl
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */
=== added file 'modules/io/zorba/modules/http-client.xq.src/curl_stream_buffer.h'
--- modules/io/zorba/modules/http-client.xq.src/curl_stream_buffer.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/curl_stream_buffer.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+#ifndef ZORBA_CURL_UTIL_H
+#define ZORBA_CURL_UTIL_H
+
+#include <zorba/config.h>
+
+#include <exception>
+#include <istream>
+#include <streambuf>
+#include <string>
+#include <curl/curl.h>
+
+namespace zorba {
+
+namespace http_client {
+ class InformDataRead;
+}
+
+namespace curl {
+
+///////////////////////////////////////////////////////////////////////////////
+
+class exception : public std::exception {
+public:
+ exception( char const *function, char const *uri, char const *msg = 0 );
+ exception( char const *function, char const *uri, CURLcode code );
+ exception( char const *function, char const *uri, CURLMcode code );
+ ~exception() throw();
+
+ virtual const char* what() const throw();
+
+private:
+ std::string msg_;
+};
+
+////////// create & destroy ///////////////////////////////////////////////////
+
+/**
+ * The signature type of cURL's write function callback.
+ */
+typedef size_t (*write_fn_t)( void*, size_t, size_t, void* );
+
+/**
+ * Creates a new, initialized cURL instance.
+ *
+ * @throws exception upon failure.
+ */
+CURL* create( char const *uri, write_fn_t fn, void *data );
+
+/**
+ * Destroys a cURL instance.
+ *
+ * @param instance A cURL instance. If \c NULL, does nothing.
+ */
+void destroy( CURL *instance );
+
+////////// streambuf //////////////////////////////////////////////////////////
+
+/**
+ * A curl::streambuf is-a std::streambuf for streaming the contents of URI
+ * using cURL. However, do not use this class directly. Use uri::streambuf
+ * instead.
+ */
+class streambuf : public std::streambuf {
+public:
+ /**
+ * Constructs a %streambuf.
+ */
+ streambuf();
+
+ /**
+ * Constructs a %streambuf and opens a connection to the server hosting the
+ * given URI for subsequent streaming.
+ *
+ * @param uri The URI to stream.
+ */
+ streambuf( char const *uri );
+
+ /**
+ * Constructs a %streambuf using an existing CURL object.
+ *
+ * @param curl The CURL object to use. This %streambuf takes ownership of
+ * it.
+ */
+ streambuf( CURL *curl );
+
+ /**
+ * Destroys a %streambuf.
+ */
+ ~streambuf();
+
+ /**
+ * Opens a connection to the server hosting the given URI for subsequent
+ * streaming.
+ *
+ * @param uri The URI to stream.
+ * @throws exception upon failure.
+ */
+ void open( char const *uri );
+
+ /**
+ * Tests whether the buffer is open.
+ *
+ * @return Returns \c true only if the buffer is open.
+ */
+ bool is_open() const {
+ return !!curl_;
+ }
+
+ /**
+ * Closes this %streambuf.
+ */
+ void close();
+
+ /**
+ * Gets the CURL object in use.
+ *
+ * @return Return said CURL object.
+ */
+ CURL* curl() const {
+ return curl_;
+ }
+
+ /**
+ * Provide a InformDataRead that will get callbacks about read events.
+ */
+ void setInformer( http_client::InformDataRead *aInformer ) {
+ theInformer = aInformer;
+ }
+
+ /**
+ * Specify whether this streambuf has memory ownership over the
+ * InformDataRead it has been passed. You can use this if, for example,
+ * the lifetime of the streambuf will extend past the lifetime of the
+ * object which created the InformDataRead.
+ */
+ void setOwnInformer( bool aOwnInformer ) {
+ theOwnInformer = aOwnInformer;
+ }
+
+ int multi_perform();
+
+protected:
+ // inherited
+ std::streamsize showmanyc();
+ int_type underflow();
+
+private:
+ void curl_read();
+ static size_t curl_write_callback( void*, size_t, size_t, void* );
+
+ void init();
+ void init_curlm();
+
+ char *buf_;
+ std::streamsize buf_capacity_;
+ std::streamoff buf_len_;
+
+ CURL *curl_;
+ CURLM *curlm_;
+ int curl_running_;
+ http_client::InformDataRead *theInformer;
+ bool theOwnInformer;
+
+ // forbid
+ streambuf( streambuf const& );
+ streambuf& operator=( streambuf const& );
+#ifdef WIN32
+ SOCKET dummy_socket_;
+#endif /* WIN32 */
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace curl
+} // namespace zorba
+#endif /* ZORBA_CURL_UTIL_H */
+/* vim:set et sw=2 ts=2: */
=== added file 'modules/io/zorba/modules/http-client.xq.src/curl_wrappers.h'
--- modules/io/zorba/modules/http-client.xq.src/curl_wrappers.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/curl_wrappers.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CURL_WRAPPERS_H
+#define CURL_WRAPPERS_H
+
+#include <curl/curl.h>
+#include <iostream>
+
+#define LOC_INFO << __FILE__ << ":" << __LINE__ << std::endl
+
+CURL* curl_easy_init_wrapped(const char* file, const int line);
+
+CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, char* char_args);
+
+CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, const char* args);
+CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, void* args);
+CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, size_t(*)(char*, size_t, size_t, void*));
+CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, size_t(*)(void*, size_t, size_t, void*));
+CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, int args);
+
+CURLMcode curl_multi_perform_wrapped(const char*file, const int line, CURLM *multi_handle, int *running_handles);
+CURLMsg* curl_multi_info_read_wrapped(const char* file, const int line, CURLM *multi_handle, int *msgs_in_queue);
+CURLMcode curl_multi_add_handle_wrapped(const char* file, const int line, CURLM *multi_handle, CURL *curl_handle);
+CURLMcode curl_multi_remove_handle_wrapped(const char* file, const int line, CURLM *multi_handle, CURL *curl_handle);
+
+void curl_slist_free_all_wrapped(const char* file, const int line, curl_slist *list);
+void curl_formfree_wrapped(const char*file, const int line, curl_httppost *form);
+
+curl_slist* curl_slist_append_wrapped(const char* file, const int line, curl_slist *list, const char *value);
+
+#endif // CURL_WRAPPERS_H
=== added file 'modules/io/zorba/modules/http-client.xq.src/error_thrower.h'
--- modules/io/zorba/modules/http-client.xq.src/error_thrower.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/error_thrower.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <zorba/zorba.h>
+#include <zorba/user_exception.h>
+#include <curl/curl.h>
+
+namespace zorba {
+namespace http_client {
+
+class ErrorThrower
+{
+private:
+ ItemFactory* theFactory;
+ struct curl_slist** theHeaderList;
+ const String& theModuleURI;
+
+public:
+ ErrorThrower(ItemFactory* aFactory, struct curl_slist** aHeaderList, const String& aModuleURI)
+ :
+ theFactory(aFactory),
+ theHeaderList(aHeaderList),
+ theModuleURI(aModuleURI)
+ {
+ }
+
+ void raiseException( String const &aNamespace, String const &aLocalName,
+ String const &aDescription )
+ {
+ if (*theHeaderList)
+ curl_slist_free_all(*theHeaderList);
+
+ throw USER_EXCEPTION(
+ theFactory->createQName(aNamespace, aLocalName), aDescription
+ );
+ }
+
+ void raiseException( String const &aLocalName,
+ String const &aDescription )
+ {
+ if (*theHeaderList)
+ curl_slist_free_all(*theHeaderList);
+
+ throw USER_EXCEPTION(
+ theFactory->createQName(theModuleURI, aLocalName), aDescription
+ );
+ }
+};
+
+} // namespace http_client
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */
=== added file 'modules/io/zorba/modules/http-client.xq.src/http_client.cpp'
--- modules/io/zorba/modules/http-client.xq.src/http_client.cpp 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/http_client.cpp 2013-06-15 00:58:33 +0000
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <curl/curl.h>
+#include <map>
+#include <zorba/zorba.h>
+#include <zorba/serializer.h>
+#include <zorba/external_module.h>
+#include <zorba/function.h>
+#include <zorba/empty_sequence.h>
+#include <zorba/user_exception.h>
+
+#include "http_request_handler.h"
+#include "request_parser.h"
+#include "http_response_handler.h"
+#include "http_response_parser.h"
+
+#ifdef WIN32
+# include <Windows.h>
+# define MAX_BUF_SIZE 2048
+#endif
+
+namespace zorba {
+
+ namespace http_client {
+#ifdef WIN32
+static void set_cacert(CURL* lCurl, std::string aPath)
+{
+ TCHAR path[MAX_BUF_SIZE];
+ int r = GetModuleFileName(NULL, path, 2048);
+ if (r == -1)
+ return;
+# ifdef UNICODE
+ char buf[MAX_BUF_SIZE];
+ memset(buf, 0, MAX_BUF_SIZE);
+ for (int i = 0; i <= r; ++i)
+ {
+ buf[i] = (char) path[i];
+ }
+ std::string lPath(buf);
+# else
+ std::string lPath(path);
+# endif
+ aPath = lPath.substr(0, lPath.rfind('\\'));
+ aPath += "\\cacert.pem";
+ if(GetFileAttributesA(aPath.c_str()) != INVALID_FILE_ATTRIBUTES)
+ curl_easy_setopt(lCurl, CURLOPT_CAINFO, aPath.c_str());
+ else
+ curl_easy_setopt(lCurl, CURLOPT_SSL_VERIFYPEER, 0L);
+}
+#endif //WIN32
+
+ class HttpSendFunction : public ContextualExternalFunction {
+ protected:
+ const ExternalModule* theModule;
+ ItemFactory* theFactory;
+
+ public:
+ HttpSendFunction(const ExternalModule* aModule)
+ : theModule(aModule),
+ theFactory(Zorba::getInstance(0)->getItemFactory()) {}
+
+ virtual ~HttpSendFunction() {}
+
+ public:
+ virtual String
+ getURI() const { return theModule->getURI(); }
+
+ virtual String
+ getLocalName() const { return "http-sequential-impl"; }
+
+ virtual ItemSequence_t
+ evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aStaticContext, const DynamicContext* aDynamicContext)
+ const;
+ };
+
+ class HttpReadFunction : public HttpSendFunction {
+ public:
+ HttpReadFunction(const ExternalModule* aModule)
+ : HttpSendFunction(aModule) {}
+
+ virtual ~HttpReadFunction() {}
+
+ public:
+ virtual String
+ getLocalName() const { return "http-nondeterministic-impl"; }
+
+ };
+
+ class HttpClientModule : public ExternalModule {
+ protected:
+ class ltstr
+ {
+ public:
+ bool operator()(const String& s1, const String& s2) const
+ {
+ return s1.compare(s2) < 0;
+ }
+ };
+
+ typedef std::map<String, ExternalFunction*, ltstr> FuncMap_t;
+
+ FuncMap_t theFunctions;
+
+ public:
+ virtual ~HttpClientModule();
+
+ HttpClientModule() : theModuleUri("http://zorba.io/modules/http-client";)
+ {
+ for (FuncMap_t::const_iterator lIter = theFunctions.begin();
+ lIter != theFunctions.end(); ++lIter) {
+ delete lIter->second;
+ }
+ theFunctions.clear();
+ }
+
+ virtual String
+ getURI() const { return theModuleUri; }
+
+ virtual ExternalFunction*
+ getExternalFunction(const String& aLocalname)
+ {
+ ExternalFunction*& lFunc = theFunctions[aLocalname];
+ if (!lFunc) {
+ if (aLocalname == "http-sequential-impl") {
+ lFunc = new HttpSendFunction(this);
+ } else if (aLocalname == "http-nondeterministic-impl") {
+ lFunc = new HttpReadFunction(this);
+ }
+ }
+ return lFunc;
+ }
+
+ virtual void
+ destroy()
+ {
+ if (!dynamic_cast<HttpClientModule*>(this)) {
+ return;
+ }
+ delete this;
+ }
+
+ private:
+ String theModuleUri;
+ };
+
+ ItemSequence_t
+ general_evaluate(
+ const ExternalFunction::Arguments_t& args,
+ const StaticContext* aStaticContext,
+ const DynamicContext* aDynamicContext,
+ ItemFactory* aFactory,
+ const String& aTheModuleURI)
+ {
+ CURL* lCURL = curl_easy_init();
+
+ Item lRequest;
+ Item lHref;
+ Item lContent;
+
+ Iterator_t arg0_iter = args[0]->getIterator();
+ arg0_iter->open();
+ bool lReqSet = arg0_iter->next(lRequest);
+ arg0_iter->close();
+
+ std::string lData;
+
+ std::auto_ptr<HttpRequestHandler> lHandler;
+ std::auto_ptr<RequestParser> lParser;
+ struct curl_slist* lHeaderList = 0;
+
+ ErrorThrower thrower(aFactory, &lHeaderList,aTheModuleURI);
+
+ if (lReqSet) {
+ lHandler.reset(new HttpRequestHandler(lCURL));
+ lParser.reset(new RequestParser(lHandler.get(), thrower, aFactory));
+ lParser->parseRequest(lRequest);
+ }
+ //curl_easy_setopt(lCURL, CURLOPT_USERAGENT, "libcurl-agent/1.0");
+ //curl_easy_setopt(lCURL, CURLOPT_PROXY, "localhost:8888");
+#ifdef WIN32
+ std::string caCertPath;
+ set_cacert(lCURL, caCertPath);
+#endif
+ HttpResponseHandler lRespHandler(aFactory, lHeaderList);
+ String lOverrideContentType;
+ if (lHandler.get())
+ lHandler->getOverrideContentType(lOverrideContentType);
+ bool lStatusOnly =
+ lHandler.get() == NULL ? false : (lHandler->isStatusOnly() || lHandler->isHeadRequest());
+ // This gives the ownership of lCurl to the HttpResponseParser
+ std::auto_ptr<HttpResponseParser> lRespParser(new HttpResponseParser(lRespHandler, lCURL, thrower,
+ lOverrideContentType.c_str(), lStatusOnly));
+ int lRetCode = lRespParser->parse();
+
+ if (lRetCode == CURLE_OPERATION_TIMEDOUT)
+ thrower.raiseException("HC006", "A timeout occurred waiting for the response");
+ else if (lRetCode)
+ {
+ thrower.raiseException("HC001", "An HTTP error occurred");
+ }
+
+ // If the Parser is "self contained", that means it didn't create any
+ // objects with a lifecycle longer than itself; therefore we should free
+ // it (by letting auto_ptr delete it). If the Parser is not self contained,
+ // then it will have arranged for some other memory manager to free it
+ // later when appropriate; therefore we should NOT let auto_ptr delete it
+ // now.
+ if ( ! lRespParser->selfContained()) {
+ lRespParser.release();
+ }
+ return ItemSequence_t(lRespHandler.releaseResult());
+ }
+
+ ItemSequence_t
+ HttpSendFunction::evaluate(const ExternalFunction::Arguments_t& args,
+ const StaticContext* aStaticContext, const DynamicContext* aDynamicContext) const
+ {
+ return general_evaluate(args, aStaticContext, aDynamicContext, theFactory, getURI());
+ }
+
+ HttpClientModule::~HttpClientModule()
+ {
+ for (FuncMap_t::const_iterator lIter = theFunctions.begin();
+ lIter != theFunctions.end(); ++lIter) {
+ delete lIter->second;
+ }
+ theFunctions.clear();
+ }
+ } // namespace http_request
+} // namespace zorba
+
+#ifdef WIN32
+# define DLL_EXPORT __declspec(dllexport)
+#else
+# define DLL_EXPORT __attribute__ ((visibility("default")))
+#endif
+
+extern "C" DLL_EXPORT zorba::ExternalModule* createModule() {
+ return new zorba::http_client::HttpClientModule();
+}
+
=== added file 'modules/io/zorba/modules/http-client.xq.src/http_request_handler.cpp'
--- modules/io/zorba/modules/http-client.xq.src/http_request_handler.cpp 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/http_request_handler.cpp 2013-06-15 00:58:33 +0000
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <cassert>
+
+#include <zorba/zorba.h>
+#include <zorba/singleton_item_sequence.h>
+#include <zorba/serializer.h>
+#include <zorba/api_shared_types.h>
+#include <zorba/xquery_functions.h>
+#include <zorba/zorba_functions.h>
+#include <zorba/base64.h>
+#include <zorba/base64_stream.h>
+#include <zorba/xquery_functions.h>
+#include <zorba/transcode_stream.h>
+
+#include "http_request_handler.h"
+
+namespace zorba { namespace http_client {
+
+ HttpRequestHandler::HttpRequestHandler(CURL* aCurl)
+ : theCurl(aCurl),
+ theStatusOnly(false),
+ theInsideMultipart(false),
+ theLastBodyHadContent(false),
+ theSerStream(NULL),
+ thePost(NULL),
+ theLast(NULL),
+ theIsHeadRequest(false)
+ {
+ theHeaderLists.push_back(NULL);
+ }
+
+ HttpRequestHandler::~HttpRequestHandler()
+ {
+ std::vector<struct curl_slist*>::iterator lIter;
+ for (lIter = theHeaderLists.begin(); lIter != theHeaderLists.end(); ++lIter)
+ {
+ if (*lIter) {
+ curl_slist_free_all(*lIter);
+ }
+ }
+
+ if (thePost != NULL) {
+ curl_formfree(thePost);
+ }
+ delete theSerStream;
+ }
+
+ void HttpRequestHandler::begin()
+ {
+ }
+
+ void HttpRequestHandler::beginResponse(int aStatus, String aMessage)
+ {
+ }
+
+ void HttpRequestHandler::endResponse()
+ {
+ }
+
+ void HttpRequestHandler::beginRequest(String aMethod,
+ String href,
+ bool aStatusOnly,
+ String aUsername,
+ String aPassword,
+ String aAuthMethod,
+ bool aSendAuthorization,
+ String aOverrideContentType,
+ bool aFollowRedirect,
+ String aUserAgent,
+ int aTimeout /*= -1*/ )
+ {
+ aMethod = fn::upper_case(aMethod);
+ const char* lStr = aMethod.c_str();
+ theMethodString = lStr;
+ String const lAuthMethod = fn::lower_case(aAuthMethod);
+ if (theMethodString == "HEAD" || theMethodString == "OPTIONS") {
+ curl_easy_setopt(theCurl, CURLOPT_NOBODY, 1L);
+ theIsHeadRequest = true;
+ }
+ curl_easy_setopt(theCurl, CURLOPT_CUSTOMREQUEST, theMethodString.c_str());
+ if (href != "") {
+ curl_easy_setopt(theCurl, CURLOPT_URL, href.c_str());
+ }
+ if (aFollowRedirect) {
+ curl_easy_setopt(theCurl, CURLOPT_FOLLOWLOCATION, 1);
+ }
+ theStatusOnly = aStatusOnly;
+ theOverrideContentType = aOverrideContentType;
+ if (aTimeout != -1) {
+ curl_easy_setopt(theCurl, CURLOPT_TIMEOUT, aTimeout);
+ }
+ if (aUserAgent != "")
+ curl_easy_setopt( theCurl, CURLOPT_USERAGENT, aUserAgent.c_str() );
+ else
+ curl_easy_setopt( theCurl, CURLOPT_USERAGENT, "libcurl-agent/1.0" );
+
+ if (aUsername != "" && !aSendAuthorization) {
+ String lUserPw = aUsername + ":" + aPassword;
+ theUserPW = lUserPw.c_str();
+ curl_easy_setopt(theCurl, CURLOPT_USERPWD, theUserPW.c_str());
+ if (lAuthMethod == "basic") {
+ curl_easy_setopt(theCurl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+ } else if (lAuthMethod == "digest") {
+ curl_easy_setopt(theCurl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
+ }
+ }
+ if (aUsername != "" && aSendAuthorization) {
+ if (lAuthMethod == "digest") {
+ String lUserPw = aUsername + ":" + aPassword;
+ theUserPW = lUserPw.c_str();
+ curl_easy_setopt(theCurl, CURLOPT_USERPWD, theUserPW.c_str());
+ curl_easy_setopt(theCurl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
+ } else {
+ String lAuthString = aUsername + ":" + aPassword;
+ String lAuth = "Authorization: ";
+ if (lAuthMethod == "basic")
+ {
+ lAuth += "Basic ";
+ }
+ else
+ {
+ lAuth += aAuthMethod + " ";
+ }
+ lAuth += encoding::Base64::encode(lAuthString);
+ theAuthMethod = lAuth.c_str();
+ theHeaderLists[0] = curl_slist_append(theHeaderLists[0], theAuthMethod.c_str());
+ }
+ }
+ }
+
+ void HttpRequestHandler::endRequest()
+ {
+ }
+
+ void HttpRequestHandler::header(String aName, String aValue)
+ {
+ std::string lValue = aName.c_str();
+ lValue += ":";
+ lValue += aValue.c_str();
+ theHeaderStrings.push_back(lValue);
+ if (!theInsideMultipart) {
+ theHeaderLists[0] = curl_slist_append(theHeaderLists[0], lValue.c_str());
+ } else {
+ if (aName == "Content-Disposition") {
+ Sequence<String> lTokens(fn::tokenize(aValue, ";"));
+ for (String lNextToken; lTokens.next( &lNextToken );) {
+ std::pair<String, String> lKeyValue = twinSplit(lNextToken);
+ if (lKeyValue.first == "name") {
+ theMultipartName = lKeyValue.second;
+ zfn::trim(theMultipartName, "\"\'");
+ }
+ else if (lKeyValue.first == "filename") {
+ theMultiPartFileName = lKeyValue.second;
+ zfn::trim(theMultiPartFileName, "\"\'");
+ }
+ }
+ } else {
+ theHeaderLists.back() = curl_slist_append(theHeaderLists.back(), (lValue).c_str());
+ }
+ }
+ }
+
+ void HttpRequestHandler::beginBody(String aContentType,
+ String aSrc,
+ ItemSequence* aSerializerOptions)
+ {
+ theLastSerializerOptions = aSerializerOptions;
+ theSerStream = new std::ostringstream();
+ theCurrentContentType = aContentType;
+ theContentType = "Content-Type: ";
+ theContentType += aContentType.c_str();
+ if (!theInsideMultipart) {
+ theHeaderLists[0] = curl_slist_append(theHeaderLists[0], theContentType.c_str());
+ } else {
+ theHeaderLists.back() = curl_slist_append(theHeaderLists.back(), theContentType.c_str());
+ }
+ }
+ void HttpRequestHandler::any(Item aItem, std::string& charset)
+ {
+ theLastBodyHadContent = true;
+ bool lTranscoderAttached = false;
+
+ switch (aItem.getTypeCode())
+ {
+ case store::XS_STRING:
+ if (!charset.empty() && transcode::is_necessary(charset.c_str()))
+ {
+ transcode::attach(*theSerStream,charset.c_str());
+ lTranscoderAttached = true;
+ }
+
+ try
+ {
+ if (aItem.isStreamable())
+ emitStreamableString(aItem);
+ else
+ emitString(aItem);
+ }
+ catch ( ... )
+ {
+ if (lTranscoderAttached)
+ transcode::detach(*theSerStream);
+ }
+
+ if (lTranscoderAttached)
+ transcode::detach(*theSerStream);
+ break;
+ case store::XS_BASE64BINARY:
+ if (aItem.isStreamable())
+ emitStreamableBase64Binary(aItem);
+ else
+ emitBase64Binary(aItem);
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+ void HttpRequestHandler::emitStreamableString(Item aItem)
+ {
+ char buffer[1024];
+ std::streambuf * pbuf;
+ std::streamsize read_bytes;
+ std::istream& is = aItem.getStream();
+ std::streampos pos;
+ std::ios::iostate const old_exceptions = is.exceptions();
+
+ if (aItem.isSeekable())
+ {
+ // prepare the stream
+ is.exceptions( std::ios::badbit | std::ios::failbit );
+ pos = is.tellg();
+ if (pos)
+ is.seekg(0, std::ios::beg);
+ is.exceptions(is.exceptions() & ~std::ios::failbit);
+ }
+
+ // read bytes and do string expansion
+ do
+ {
+ //std::istream::read uses a try/catch internally so the Zorba_Exception is
+ //lost: that is why we are using std::streambuf::sgetn
+ pbuf = is.rdbuf();
+ read_bytes = pbuf->sgetn(buffer, 1024);
+ theSerStream->write(buffer, read_bytes);
+ }
+ while (read_bytes > 0);
+
+ // restore stream's state
+ is.clear(); // clear eofbit
+ if (aItem.isSeekable())
+ {
+ if (pos)
+ {
+ is.exceptions(is.exceptions() | std::ios::failbit);
+ is.seekg(pos, std::ios::beg);
+ }
+ is.exceptions(old_exceptions);
+ }
+ }
+
+ void HttpRequestHandler::emitString(Item aItem)
+ {
+ *theSerStream << aItem.getStringValue();
+ }
+
+ void HttpRequestHandler::emitStreamableBase64Binary(Item aItem)
+ {
+ std::istream& stream = aItem.getStream();
+ bool lDecoderAttached = false;
+
+ if (aItem.isEncoded())
+ {
+ base64::attach(stream);
+ lDecoderAttached = true;
+ }
+
+ char buf[1024];
+ while (!stream.eof())
+ {
+ stream.read(buf, 1024);
+ theSerStream->write(buf, stream.gcount());
+ }
+
+ if (lDecoderAttached)
+ base64::detach(stream);
+ }
+
+ void HttpRequestHandler::emitBase64Binary(Item aItem)
+ {
+ size_t lLen = 0;
+ const char * lData = aItem.getBase64BinaryValue(lLen);
+ if (aItem.isEncoded())
+ {
+ String lEncoded(lData,lLen);
+ String lDecodedData = encoding::Base64::decode(lEncoded);
+ *theSerStream << lDecodedData;
+ }
+ else
+ {
+ theSerStream->write(lData,lLen);
+ }
+ }
+
+ void HttpRequestHandler::endBody()
+ {
+ if (!theLastBodyHadContent)
+ {
+ cleanUpBody();
+ return;
+ }
+ thePostDataString = theSerStream->str();
+ thePostData = thePostDataString.c_str();
+ if (!theInsideMultipart) {
+ curl_easy_setopt(theCurl, CURLOPT_POSTFIELDSIZE, thePostDataString.length());
+ curl_easy_setopt(theCurl, CURLOPT_POSTFIELDS, thePostData);
+ } else {
+ if (theMultiPartFileName == "")
+ curl_formadd(&thePost, &theLast,
+ CURLFORM_COPYNAME, theMultipartName.c_str(),
+ CURLFORM_COPYCONTENTS, thePostData,
+ CURLFORM_CONTENTSLENGTH, thePostDataString.length(),
+ CURLFORM_CONTENTHEADER, theHeaderLists.back(),
+ CURLFORM_END);
+ else
+ curl_formadd(&thePost, &theLast,
+ CURLFORM_COPYNAME, theMultipartName.c_str(),
+ CURLFORM_BUFFER, theMultiPartFileName.c_str(),
+ CURLFORM_BUFFERPTR, thePostData,
+ CURLFORM_BUFFERLENGTH, thePostDataString.length(),
+ CURLFORM_CONTENTHEADER, theHeaderLists.back(),
+ CURLFORM_END);
+ theHeaderLists.push_back(NULL);
+ }
+ }
+
+ void HttpRequestHandler::beginMultipart(String aContentType, String aBoundary)
+ {
+ theMultiPartFileName = "";
+ theMultipartName = "zorba-default";
+ theInsideMultipart = true;
+ std::string lValue = "Content-Type: ";
+ lValue += aContentType.c_str();
+ theHeaderStrings.push_back (lValue);
+ theHeaderLists[0] = curl_slist_append(theHeaderLists[0], lValue.c_str());
+ theHeaderLists.push_back(NULL);
+ }
+
+ void HttpRequestHandler::endMultipart()
+ {
+ theInsideMultipart = false;
+ curl_easy_setopt(theCurl, CURLOPT_HTTPPOST, thePost);
+ }
+
+ void HttpRequestHandler::end()
+ {
+ if (theHeaderLists[0]) {
+ curl_easy_setopt(theCurl, CURLOPT_HTTPHEADER, theHeaderLists[0]);
+ }
+ }
+
+ bool HttpRequestHandler::getOverrideContentType( String& aResult )
+ {
+ if (theOverrideContentType == "") {
+ return false;
+ }
+ aResult = theOverrideContentType;
+ return true;
+ }
+
+ void HttpRequestHandler::cleanUpBody()
+ {
+ delete theSerStream;
+ theSerStream = 0;
+ theLastBodyHadContent = false;
+ }
+
+ void HttpRequestHandler::serializeItem( Item aItem )
+ {
+ theLastBodyHadContent = true;
+ Serializer_t lSerializer =
+ Serializer::createSerializer(theLastSerializerOptions);
+ SingletonItemSequence lSequence(aItem);
+ lSerializer->serialize(&lSequence, *theSerStream);
+ }
+
+ std::pair<String, String>
+ HttpRequestHandler::twinSplit(const String& aStr)
+ {
+ String lKey, lValue;
+
+ String::size_type const equals = aStr.find('=');
+ if (equals != String::npos) {
+ lKey = aStr.substr(0, equals);
+ lValue = aStr.substr(equals + 1);
+ zfn::trim(lKey);
+ zfn::trim(lValue);
+ }
+
+ return std::pair<String, String>(lKey, lValue);
+ }
+
+} // namespace http_client
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */
=== added file 'modules/io/zorba/modules/http-client.xq.src/http_request_handler.h'
--- modules/io/zorba/modules/http-client.xq.src/http_request_handler.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/http_request_handler.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef HTTP_REQUEST_HANDLER_H
+#define HTTP_REQUEST_HANDLER_H
+
+#include <sstream>
+#include <vector>
+#include <string>
+
+#include <curl/curl.h>
+#include <zorba/zorba.h>
+
+#include "request_handler.h"
+
+namespace zorba { namespace http_client {
+
+ class HttpRequestHandler : public RequestHandler {
+ private:
+ CURL* theCurl;
+ bool theStatusOnly;
+ String theOverrideContentType;
+ bool theInsideMultipart;
+ std::vector<struct curl_slist*> theHeaderLists;
+ bool theLastBodyHadContent;
+ std::ostringstream* theSerStream;
+ struct curl_httppost* thePost;
+ struct curl_httppost* theLast;
+ String theCurrentContentType;
+ ItemSequence* theLastSerializerOptions;
+ std::string thePostDataString;
+ const char* thePostData;
+ long thePostDataSize;
+ String theMultipartName;
+ String theMultiPartFileName;
+ // saved strings which won't be copied by curl
+ std::string theMethodString;
+ std::string theUserPW;
+ std::string theAuthMethod;
+ std::vector<std::string> theHeaderStrings;
+ std::string theContentType;
+ bool theIsHeadRequest;
+
+ public: //Constructions
+ HttpRequestHandler(CURL* aCurl);
+ virtual ~HttpRequestHandler();
+
+ public: //Interfaces
+ /**
+ * @brief Get the override-content-type option.
+ *
+ * If the user set the override-content-type option, this method will
+ * set the result to the user specified value and will return true.
+ * Otherwise it will return false.
+ *
+ * @param aResult The override-content-type option, if set.
+ * @return A boolean indicating if the override-content-type is set.
+ */
+ bool getOverrideContentType(String& aResult);
+
+ public: //Implementation of parent interface
+ virtual void begin();
+ virtual void beginResponse(int aStatus, String aMessage);
+ virtual void endResponse();
+ virtual void beginRequest(
+ String aMethod,
+ String href,
+ bool aStatusOnly,
+ String aUsername,
+ String aPassword,
+ String aAuthMethod,
+ bool aSendAuthorization,
+ String aOverrideContentType,
+ bool aFollowRedirect,
+ String aUserAgent,
+ int aTimeout = -1);
+ virtual void endRequest();
+ virtual void header(String aName, String aValue);
+ virtual void beginBody(
+ String aContentType,
+ String aSrc,
+ ItemSequence* aSerializerOptions);
+ virtual void any(Item aItem, std::string& charset);
+
+ virtual void emitStreamableString(Item aItem);
+ virtual void emitString(Item aItem);
+ virtual void emitStreamableBase64Binary(Item aItem);
+ virtual void emitBase64Binary(Item aItem);
+
+
+ void serializeItem( Item aItem );
+ virtual void endBody();
+ virtual void beginMultipart(String aContentType, String aBoundary);
+ virtual void endMultipart();
+ virtual void end();
+
+ bool isStatusOnly() const { return theStatusOnly; }
+ virtual bool isHeadRequest() const { return theIsHeadRequest; }
+
+ private: //Helper functions
+ void cleanUpBody();
+ static std::pair<String, String> twinSplit(const String& aStr);
+ };
+
+}}
+
+#endif //HTTP_REQUEST_HANDLER_H
=== added file 'modules/io/zorba/modules/http-client.xq.src/http_response_handler.cpp'
--- modules/io/zorba/modules/http-client.xq.src/http_response_handler.cpp 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/http_response_handler.cpp 2013-06-15 00:58:33 +0000
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <zorba/xquery_exception.h>
+#include <zorba/item.h>
+#include <zorba/item_factory.h>
+#include <zorba/zorba_string.h>
+
+#include "http_response_handler.h"
+#include "http_response_parser.h"
+
+namespace zorba { namespace http_client {
+
+ //////////////////////////////////////////////////////////////////////////
+ // HttpResponseIterator
+ //////////////////////////////////////////////////////////////////////////
+
+ const char* theNamespace = "http://expath.org/ns/http-client";;
+
+ HttpResponseIterator::HttpResponseIterator(curl_slist* aHeaderList)
+ : theResponseSet(false), theHeaderList(aHeaderList)
+ {
+ // Set an empty item as the response item
+ theItems.push_back(Item());
+ }
+
+ HttpResponseIterator::~HttpResponseIterator()
+ {
+ if (theHeaderList)
+ curl_slist_free_all(theHeaderList);
+ }
+
+ Iterator_t HttpResponseIterator::getIterator()
+ {
+ return new InternalIterator(this);
+ }
+
+ HttpResponseIterator::InternalIterator::InternalIterator(HttpResponseIterator *item_sequence) :
+ theItemSequence(item_sequence),
+ theIndex(0)
+ {
+ is_open = false;
+ }
+
+ void HttpResponseIterator::InternalIterator::open()
+ {
+ theIndex = 0;
+ is_open = true;
+ }
+
+ void HttpResponseIterator::InternalIterator::close()
+ {
+ is_open = false;
+ }
+
+ bool HttpResponseIterator::InternalIterator::isOpen() const
+ {
+ return is_open;
+ }
+
+ bool HttpResponseIterator::InternalIterator::next( Item& aItem )
+ {
+ if (!theItemSequence->theResponseSet) {
+ return false;
+ }
+ if (theIndex < theItemSequence->theItems.size()) {
+ aItem = theItemSequence->theItems[theIndex];
+ ++theIndex;
+ return !aItem.isNull();
+ }
+ return false;
+ }
+
+ void HttpResponseIterator::addItem(const Item& aItem)
+ {
+ theItems.push_back(aItem);
+ }
+
+ void HttpResponseIterator::setResponseItem(const Item& aItem)
+ {
+ theItems[0] = aItem;
+ theResponseSet = true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // HttpResponseHandler
+ //////////////////////////////////////////////////////////////////////////
+
+ HttpResponseHandler::HttpResponseHandler(ItemFactory* aFactory, curl_slist* aHeaderList)
+ :
+ theResult(new HttpResponseIterator(aHeaderList)),
+ theFactory(aFactory),
+ theIsInsideMultipart(false),
+ theDeleteResponse(true)
+ {
+ theUntypedQName = theFactory->createQName("http://www.w3.org/2001/XMLSchema";, "untyped");
+ }
+
+ HttpResponseHandler::~HttpResponseHandler() {
+ if (theDeleteResponse) {
+ delete theResult;
+ }
+ }
+
+ void HttpResponseHandler::begin()
+ {
+ }
+
+ void HttpResponseHandler::beginResponse(int aStatus, String aMessage)
+ {
+ Item lStatusName = theFactory->createString("status");
+ Item lStatusValue = theFactory->createInteger(aStatus);
+
+ Item lMessageName = theFactory->createString("message");
+ Item lMessageValue = theFactory->createString(aMessage);
+
+ theResponsePairs.push_back(std::pair<Item, Item>(lStatusName, lStatusValue));
+ theResponsePairs.push_back(std::pair<Item, Item>(lMessageName, lMessageValue));
+ }
+
+ void HttpResponseHandler::endResponse()
+ {
+ if (theResponseHeaderMap.size()>0)
+ {
+ Item lHeadersName = theFactory->createString("headers");
+ std::vector<std::pair<Item,Item> > lHeadersPairs;
+
+ std::map<String,String>::iterator it = theResponseHeaderMap.begin();
+ std::map<String,String>::iterator end = theResponseHeaderMap.end();
+ Item lName;
+ Item lValue;
+ for (;it!=end;++it)
+ {
+ lName = theFactory->createString(it->first);
+ lValue = theFactory->createString(it->second);
+ lHeadersPairs.push_back(std::pair<Item,Item>(lName,lValue));
+ }
+ Item lHeaders = theFactory->createJSONObject(lHeadersPairs);
+ theResponsePairs.push_back(std::pair<Item,Item>(lHeadersName,lHeaders));
+ }
+
+ Item lResponse = theFactory->createJSONObject(theResponsePairs);
+ theResult->setResponseItem(lResponse);
+ }
+
+ // Since this class is only used to handle responses, beginRequest and
+ // endRequest are not implemented.
+ void HttpResponseHandler::beginRequest(String aMethod,
+ String href,
+ bool aStatusOnly,
+ String aUsername,
+ String aPassword,
+ String aAuthMethod,
+ bool aSendAuthorization,
+ String aOverrideContentType,
+ bool aFollowRedirect,
+ String aUserAgent,
+ int aTimeout /*= -1*/)
+ {
+ }
+
+ void HttpResponseHandler::endRequest()
+ {
+ }
+
+ void HttpResponseHandler::header(String aName, String aValue)
+ {
+ std::map<String, String>& lHeaderMap =
+ theIsInsideMultipart ? theMultipartHeaderMap : theResponseHeaderMap;
+
+ if (lHeaderMap.find(aName)!=lHeaderMap.end())
+ lHeaderMap[aName] = lHeaderMap[aName] + "," +aValue;
+ else
+ lHeaderMap[aName] = aValue;
+ }
+
+ void HttpResponseHandler::beginBody(String aContentType,
+ String aSrc,
+ ItemSequence* aSerializerOptions)
+ {
+ std::vector<std::pair<Item, Item> >& lBodyPairs =
+ theIsInsideMultipart ? theMultipartBodyPairs : theBodyPairs;
+
+ Item lName = theFactory->createString("media-type");
+ Item lValue = theFactory->createString(aContentType);
+
+ lBodyPairs.push_back(std::pair<Item, Item>(lName,lValue));
+ }
+
+ void HttpResponseHandler::any(Item aItem, std::string& charset)
+ {
+ std::vector<std::pair<Item, Item> >& lBodyPairs =
+ theIsInsideMultipart ? theMultipartBodyPairs : theBodyPairs;
+ Item lContentName = theFactory->createString("content");
+ lBodyPairs.push_back(std::pair<Item,Item>(lContentName,aItem));
+ }
+
+ void HttpResponseHandler::endBody()
+ {
+ std::vector<std::pair<Item, Item> >& lBodyPairs =
+ theIsInsideMultipart ? theMultipartBodyPairs : theBodyPairs;
+
+ Item lBody = theFactory->createJSONObject(lBodyPairs);
+ if (theIsInsideMultipart)
+ {
+ std::vector<std::pair<Item,Item> > lPartsPairs;
+ if (theMultipartHeaderMap.size()>0)
+ {
+ Item lHeadersName = theFactory->createString("headers");
+ std::vector<std::pair<Item,Item> > lHeadersPairs;
+
+ std::map<String,String>::iterator it = theMultipartHeaderMap.begin();
+ std::map<String,String>::iterator end = theMultipartHeaderMap.end();
+ Item lName;
+ Item lValue;
+ for (; it != end; ++it)
+ {
+ lName = theFactory->createString(it->first);
+ lValue = theFactory->createString(it->second);
+ lHeadersPairs.push_back(std::pair<Item, Item>(lName, lValue));
+ }
+
+ Item lHeaders = theFactory->createJSONObject(lHeadersPairs);
+ lPartsPairs.push_back(std::pair<Item,Item>(lHeadersName,lHeaders));
+ theMultipartHeaderMap = std::map<String, String>();
+ }
+
+ Item lBodyName = theFactory->createString("body");
+ lPartsPairs.push_back(std::pair<Item,Item>(lBodyName,lBody));
+ Item lPart = theFactory->createJSONObject(lPartsPairs);
+ theMultipartBodyVector.push_back(lPart);
+ }
+ else
+ {
+ Item lName = theFactory->createString("body");
+ theResponsePairs.push_back(std::pair<Item,Item>(lName,lBody));
+ }
+ }
+
+ void HttpResponseHandler::beginMultipart(String aContentType, String aBoundary)
+ {
+ theIsInsideMultipart = true;
+
+ Item lContentTypeName = theFactory->createString("content-type");
+ Item lContentTypeValue = theFactory->createString(aContentType);
+
+ theMultipartPairs.push_back(std::pair<Item,Item>(lContentTypeName, lContentTypeValue));
+
+ Item lBoundaryName = theFactory->createString("boundary");
+ Item lBoundaryValue = theFactory->createString(aBoundary);
+
+ theMultipartPairs.push_back(std::pair<Item,Item>(lBoundaryName, lBoundaryValue));
+ }
+
+ void HttpResponseHandler::endMultipart()
+ {
+ theIsInsideMultipart = false;
+ Item lBodyName = theFactory->createString("parts");
+ Item lBodyArray = theFactory->createJSONArray(theMultipartBodyVector);
+
+ theMultipartPairs.push_back(std::pair<Item,Item>(lBodyName,lBodyArray));
+ Item lName = theFactory->createString("multipart");
+ Item lMultipart = theFactory->createJSONObject(theMultipartBodyPairs);
+ theResponsePairs.push_back(std::pair<Item,Item>(lName,lMultipart));
+ }
+
+ void HttpResponseHandler::end()
+ {
+ }
+
+ HttpResponseIterator* HttpResponseHandler::getResult()
+ {
+ return theResult;
+ }
+
+ HttpResponseIterator* HttpResponseHandler::releaseResult()
+ {
+ theDeleteResponse = false;
+ return theResult;
+ }
+}} //namespace zorba, namespace http_client
=== added file 'modules/io/zorba/modules/http-client.xq.src/http_response_handler.h'
--- modules/io/zorba/modules/http-client.xq.src/http_response_handler.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/http_response_handler.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef HTTP_RESPONSE_HANDLER_H
+#define HTTP_RESPONSE_HANDLER_H
+
+#include <vector>
+#include <string>
+#include <map>
+#include <curl/curl.h>
+
+#include <zorba/item_sequence.h>
+#include <zorba/iterator.h>
+
+#include "request_handler.h"
+
+namespace zorba {
+class Item;
+class ItemFactory;
+namespace http_client {
+ class HttpResponseParser;
+
+ class HttpResponseIterator : public ItemSequence {
+ class InternalIterator : public Iterator
+ {
+ private:
+ HttpResponseIterator* theItemSequence;
+ std::vector<Item>::size_type theIndex;
+ bool is_open;
+ public:
+ InternalIterator(HttpResponseIterator *item_sequence);
+
+ virtual void open();
+ virtual bool next(Item& aItem);
+ virtual void close();
+ virtual bool isOpen() const;
+ };
+ private:
+ std::vector<Item> theItems;
+ bool theResponseSet;
+ public:
+ HttpResponseIterator(curl_slist* aHeaderList);
+ virtual ~HttpResponseIterator();
+
+ public:
+ virtual Iterator_t getIterator();
+
+ public: //Implementation specific functions
+ void addItem(const Item& aItem);
+ void setResponseItem(const Item& aItem);
+
+ public:
+ static void streamReleaser(std::istream* aStream);
+
+ private:
+ curl_slist* theHeaderList;
+ };
+
+ class HttpResponseHandler : public RequestHandler {
+ private:
+ HttpResponseIterator* theResult;
+ std::vector<std::pair<Item, Item> > theResponsePairs;
+
+ std::map<String, String> theResponseHeaderMap;
+ std::map<String, String> theMultipartHeaderMap;
+
+ std::vector<std::pair<Item, Item> > theMultipartPairs;
+
+ std::vector<std::pair<Item, Item> > theBodyPairs;
+ std::vector<std::pair<Item, Item> > theMultipartBodyPairs;
+
+ std::vector<Item> theMultipartBodyVector;
+
+ ItemFactory* theFactory;
+ bool theIsInsideMultipart;
+ bool theDeleteResponse;
+ Item theUntypedQName;
+ public:
+ HttpResponseHandler(ItemFactory* aFactory, curl_slist* theHeaderList);
+ virtual ~HttpResponseHandler();
+ public:
+ HttpResponseIterator* getResult();
+ HttpResponseIterator* releaseResult();
+ public: //Interface implementation
+ virtual void begin();
+ virtual void beginResponse(int aStatus, String aMessage);
+ virtual void endResponse();
+ virtual void beginRequest(
+ String aMethod,
+ String href,
+ bool aStatusOnly,
+ String aUsername,
+ String aPassword,
+ String aAuthMethod,
+ bool aSendAuthorization,
+ String aOverrideContentType,
+ bool aFollowRedirect,
+ String aUserAgent,
+ int aTimeout = -1);
+ virtual void endRequest();
+ virtual void header(String aName, String aValue);
+ virtual void beginBody(
+ String aContentType,
+ String aSrc,
+ ItemSequence* aSerializerOptions);
+ virtual void any(Item aItem, std::string& charset);
+ virtual void endBody();
+ virtual void beginMultipart(String aContentType, String aBoundary);
+ virtual void endMultipart();
+ virtual void end();
+ virtual bool isHeadRequest() const { return false; }
+ };
+}} //namespace zorba, namespace http_client
+
+#endif //HTTP_RESPONSE_HANDLER_H
=== added file 'modules/io/zorba/modules/http-client.xq.src/http_response_parser.cpp'
--- modules/io/zorba/modules/http-client.xq.src/http_response_parser.cpp 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/http_response_parser.cpp 2013-06-15 00:58:33 +0000
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cassert>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+#include <zorba/base64.h>
+#include <zorba/config.h>
+#include <zorba/diagnostic_list.h>
+#include <zorba/error.h>
+#include <zorba/item.h>
+#include <zorba/item_factory.h>
+#include <zorba/transcode_stream.h>
+#include <zorba/xmldatamanager.h>
+#include <zorba/xquery_exception.h>
+#include <zorba/xquery_exception.h>
+#include <zorba/xquery_functions.h>
+
+#include "http_response_parser.h"
+#include "http_request_handler.h"
+#include "curl_stream_buffer.h"
+
+namespace zorba {
+
+namespace http_client {
+
+void parse_content_type( std::string const &s, std::string *mime_type,
+ std::string *charset ) {
+ std::string::size_type pos = s.find( ';' );
+ *mime_type = s.substr( 0, pos );
+
+ if ( std::strncmp( mime_type->c_str(), "text/", 5 ) == 0 ) {
+ //
+ // RFC 2616: "Hypertext Transfer Protocol -- HTTP/1.1," section 3.7.1,
+ // "Canonicalization and Text Defaults":
+ //
+ // The "charset" parameter is used with some media types to define the
+ // character set (section 3.4) of the data. When no explicit charset
+ // parameter is provided by the sender, media subtypes of the "text"
+ // type are defined to have a default charset value of "ISO-8859-1" when
+ // received via HTTP.
+ //
+ *charset = "ISO-8859-1";
+ } else
+ charset->clear();
+
+ if ( pos != std::string::npos ) {
+ //
+ // Parse: charset="?XXXXX"?[ (comment)]
+ //
+ if ( (pos = s.find( '=' )) != std::string::npos ) {
+ std::string t = s.substr( pos + 1 );
+ if ( !t.empty() ) {
+ if ( t[0] == '"' ) {
+ t.erase( 0, 1 );
+ if ( (pos = t.find( '"' )) != std::string::npos )
+ t.erase( pos );
+ } else {
+ if ( (pos = t.find( ' ' )) != std::string::npos )
+ t.erase( pos );
+ }
+ *charset = t;
+ }
+ }
+ }
+}
+
+
+
+ HttpResponseParser::HttpResponseParser(RequestHandler& aHandler, CURL* aCurl,
+ ErrorThrower& aErrorThrower,
+ std::string aOverridenContentType,
+ bool aStatusOnly) :
+ theHandler(aHandler),
+ theCurl(aCurl),
+ theErrorThrower(aErrorThrower),
+ theStatus(-1),
+ theStreamBuffer(0),
+ theInsideRead(false),
+ theOverridenContentType(aOverridenContentType),
+ theStatusOnly(aStatusOnly),
+ theSelfContained(true)
+ {
+ registerHandler();
+ theStreamBuffer = new zorba::curl::streambuf(theCurl);
+ }
+
+ HttpResponseParser::~HttpResponseParser()
+ {
+ delete theStreamBuffer;
+ }
+
+ int HttpResponseParser::parse()
+ {
+ theStreamBuffer->setInformer(this);
+ theHandler.begin();
+ bool lStatusAndMesssageParsed = false;
+ int lCode = 0;
+ lCode = theStreamBuffer->multi_perform();
+ if (lCode)
+ return lCode;
+ if (!theStatusOnly) {
+
+ if (!theOverridenContentType.empty()) {
+ parse_content_type(
+ theOverridenContentType, &theCurrentContentType, &theCurrentCharset
+ );
+ }
+
+ std::auto_ptr<std::istream> lStream;
+ try {
+ if ( !theCurrentCharset.empty() &&
+ transcode::is_necessary( theCurrentCharset.c_str() ) ) {
+ lStream.reset(
+ new transcode::stream<std::istream>(
+ theCurrentCharset.c_str(), theStreamBuffer
+ )
+ );
+ } else
+ lStream.reset(new std::istream(theStreamBuffer));
+ }
+ catch ( std::invalid_argument const &e ) {
+ theErrorThrower.raiseException(
+ "http://www.zorba-xquery.com/errors";, "ZXQP0006", e.what()
+ );
+ }
+
+ Item lItem;
+ if (theCurrentContentType == "application/xml" ||
+ theCurrentContentType == "application/xml-external-parsed-entity" ||
+ theCurrentContentType == "application/json" ||
+ theCurrentContentType == "application/x-javascript" ||
+ theCurrentContentType == "text/javascript" ||
+ theCurrentContentType == "text/x-javascript" ||
+ theCurrentContentType == "text/x-json" ||
+ theCurrentContentType.find("+xml") == theCurrentContentType.size()-4 ||
+ theCurrentContentType.find("text/") == 0)
+ {
+ lItem = createTextItem(lStream.release());
+ }
+ else
+ {
+ lItem = createBase64Item(*lStream.get());
+ }
+
+ if (!lItem.isNull()) {
+ std::string empty;
+ theHandler.any(lItem, empty);
+ }
+ if (!theInsideRead) {
+ theHandler.beginResponse(theStatus, theMessage);
+ lStatusAndMesssageParsed = true;
+ } else {
+ theHandler.endBody();
+ }
+ }
+ if (!theInsideRead) {
+ if (!lStatusAndMesssageParsed)
+ theHandler.beginResponse(theStatus, theMessage);
+ for (std::vector<std::pair<std::string, std::string> >::iterator i = theHeaders.begin();
+ i != theHeaders.end(); ++i) {
+ theHandler.header(i->first, i->second);
+ }
+ }
+ theHandler.endResponse();
+ theHandler.end();
+ return lCode;
+ }
+
+ void HttpResponseParser::beforeRead()
+ {
+ if (theInsideRead) {
+ return;
+ }
+ theInsideRead = true;
+ theHandler.beginResponse(theStatus, theMessage);
+ for ( headers_type::const_iterator
+ lIter = theHeaders.begin(); lIter != theHeaders.end(); ++lIter) {
+ theHandler.header(lIter->first, lIter->second);
+ }
+ if (!theStatusOnly)
+ theHandler.beginBody(theCurrentContentType, "", NULL);
+ }
+
+ void HttpResponseParser::afterRead()
+ {
+ }
+
+ void HttpResponseParser::registerHandler()
+ {
+ curl_easy_setopt(theCurl, CURLOPT_HEADERFUNCTION, &curl_headerfunction);
+ curl_easy_setopt(theCurl, CURLOPT_HEADERDATA, this);
+ }
+
+ size_t HttpResponseParser::curl_headerfunction( void *ptr, size_t size,
+ size_t nmemb, void *data )
+ {
+ size_t lSize = size*nmemb;
+ size_t lResult = lSize;
+ HttpResponseParser* lParser = static_cast<HttpResponseParser*>(data);
+ if (lParser->theInsideRead) {
+ lParser->theHandler.endBody();
+ lParser->theInsideRead = false;
+ }
+ const char* lDataChar = (const char*) ptr;
+ while (lSize != 0 && (lDataChar[lSize - 1] == 10
+ || lDataChar[lSize - 1] == 13)) {
+ lSize--;
+ }
+ if (lSize == 0) {
+ return lResult;
+ }
+ std::string lData(lDataChar, lSize);
+
+ if (lData.find("HTTP") == 0) {
+ lParser->parseStatusAndMessage(lData);
+ return lResult;
+ }
+ std::string::size_type lPos = lData.find(':');
+ if (lPos == std::string::npos) {
+ return lResult;
+ }
+ std::string lName = lData.substr(0, lPos);
+ std::string lValue = lData.substr(lPos + 2);
+ {
+ std::string::size_type lPosition = lValue.size() - 1;
+ while (true) {
+ if (lPosition != std::string::npos) {
+ break;
+ }
+ if (lValue[lPosition] == '\n' || lValue[lPosition] == '\r') {
+ --lPosition;
+ } else {
+ break;
+ }
+ }
+ lValue = lValue.substr(0, lPosition + 1);
+ }
+ String lNameS = fn::lower_case( lName );
+ if (lNameS == "content-type") {
+ parse_content_type(
+ lValue, &lParser->theCurrentContentType, &lParser->theCurrentCharset
+ );
+ } else if (lNameS == "content-id") {
+ lParser->theId = lValue;
+ } else if (lNameS == "content-description") {
+ lParser->theDescription = lValue;
+ }
+ lParser->theHeaders.push_back(
+ std::pair<std::string, std::string>(lName, lValue));
+ return lResult;
+ }
+
+ void HttpResponseParser::parseStatusAndMessage(std::string const &aHeader)
+ {
+ std::string::size_type lPos = aHeader.find(' ');
+ assert(lPos != std::string::npos);
+ std::string lStatus = aHeader.substr(lPos, aHeader.find(' ', lPos + 1));
+ theMessage = aHeader.substr(aHeader.find(' ', lPos + 1) + 1);
+ {
+ std::string::size_type lPosition = theMessage.size() - 1;
+ while (true) {
+ if (lPosition != std::string::npos) {
+ break;
+ }
+ if (theMessage[lPosition] == '\n' || theMessage[lPosition] == '\r') {
+ --lPosition;
+ } else {
+ break;
+ }
+ }
+ theMessage = theMessage.substr(0, lPosition + 1);
+ }
+ std::stringstream lStream(lStatus);
+ lStream >> theStatus;
+ // everything that is not a valid http status is an error
+ if (theStatus < 100) {
+ theErrorThrower.raiseException("HC001", "An HTTP error occurred");
+ }
+ }
+
+ static void streamReleaser(std::istream* aStream)
+ {
+ if (!aStream)
+ return;
+
+ // This istream contains our curl stream buffer, so we have to delete it too
+ std::streambuf *const sbuf = aStream->rdbuf();
+ if ( transcode::streambuf *tbuf =
+ dynamic_cast<transcode::streambuf*>( sbuf ) )
+ delete tbuf->orig_streambuf();
+ else
+ delete sbuf;
+ delete aStream;
+ }
+
+ zorba::Item HttpResponseParser::createTextItem(std::istream* aStream)
+ {
+ ItemFactory* lFactory = Zorba::getInstance(0)->getItemFactory();
+
+ // When we create a StreamableString, memory ownership gets very convoluted
+ // because the StreamableString object has a longer lifecycle than the
+ // iterator which creates it. The StreamableString object depends on its
+ // istream, which in turn depends on its read buffer. For us, the read
+ // buffer in turn depends on the HttpResponseParser (this object) because
+ // it is registered as the "informer" (callback object) for
+ // theStreamBuffer. Therefore, this HttpResponseParser object is no longer
+ // "self-contained". We delegate ownership of ourself to theStreamBuffer
+ // and mark ourselves as no longer being self-contained.
+ theStreamBuffer->setOwnInformer(true);
+ theSelfContained = false;
+
+ // The ownership of theStreamBuffer, in turn, is delegated to the
+ // StreamableString object (via streamReleaser, which will free the
+ // istream's rdbuf).
+ theStreamBuffer = NULL;
+ return lFactory->createStreamableString(*aStream, &streamReleaser, false);
+ }
+
+ zorba::Item HttpResponseParser::createBase64Item( std::istream& aStream )
+ {
+ ItemFactory* lFactory = Zorba::getInstance(0)->getItemFactory();
+ // TODO: once a proper streaming implementation is in place this can be
+ // changed. This required a Base64 encoding stream since the item factory
+ // work only builds base64binary and assumes the data is already encoded.
+ String lEncoded = encoding::Base64::encode(aStream);
+ return lFactory->createBase64Binary(lEncoded.data(), lEncoded.size());
+ }
+
+} // namespace http_client
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */
=== added file 'modules/io/zorba/modules/http-client.xq.src/http_response_parser.h'
--- modules/io/zorba/modules/http-client.xq.src/http_response_parser.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/http_response_parser.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef HTTP_RESPONSE_PARSER_H
+#define HTTP_RESPONSE_PARSER_H
+#include <vector>
+#include <string>
+#include <map>
+
+#include <curl/curl.h>
+
+#include "inform_data_read.h"
+#include "error_thrower.h"
+#include "http_response_handler.h"
+
+namespace zorba {
+class Item;
+
+namespace curl {
+ class streambuf;
+}
+
+namespace http_client
+{
+ void parse_content_type( std::string const &s, std::string *mime_type, std::string *charset );
+
+ class RequestHandler;
+
+ class HttpResponseParser : public InformDataRead {
+ private:
+ RequestHandler& theHandler;
+ CURL* theCurl;
+ ErrorThrower& theErrorThrower;
+ std::string theCurrentContentType;
+ std::string theCurrentCharset;
+ typedef std::vector<std::pair<std::string, std::string> > headers_type;
+ headers_type theHeaders;
+ int theStatus;
+ std::string theMessage;
+ zorba::curl::streambuf* theStreamBuffer;
+ std::string theId;
+ std::string theDescription;
+ bool theInsideRead;
+ std::map<std::string, std::string> theCodeMap;
+ std::string theOverridenContentType;
+ bool theStatusOnly;
+ bool theSelfContained;
+ public:
+ HttpResponseParser(
+ RequestHandler& aHandler,
+ CURL* aCurl,
+ ErrorThrower& aErrorThrower,
+ std::string aOverridenContentType = "",
+ bool aStatusOnly = false);
+ virtual ~HttpResponseParser();
+ int parse();
+ /**
+ * After calling parse(), it is possible that HttpResponseParser will have
+ * created some long-lived objects that depend on it. In that case, it will
+ * also have arranged for itself to be de-allocated at some future time
+ * when it is appropriate to do so. Therefore, in this case, the code which
+ * created the HttpResponseParser should NOT free it. HttpResponseParser
+ * refers to itself as "not self-contained" in this case, and this method
+ * will return false.
+ */
+ bool selfContained() { return theSelfContained; }
+ virtual void beforeRead();
+ virtual void afterRead();
+ private:
+ void registerHandler();
+ void parseStatusAndMessage(std::string const &aHeader);
+ Item createTextItem(std::istream* aStream);
+ Item createBase64Item(std::istream& aStream);
+
+ static size_t curl_headerfunction( void*, size_t, size_t, void* );
+ };
+
+} // namespace http_client
+} // namespace zorba
+
+#endif //HTTP_RESPONSE_PARSER_H
=== added file 'modules/io/zorba/modules/http-client.xq.src/inform_data_read.cpp'
--- modules/io/zorba/modules/http-client.xq.src/inform_data_read.cpp 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/inform_data_read.cpp 2013-06-15 00:58:33 +0000
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "inform_data_read.h"
+
+namespace zorba { namespace http_client {
+ InformDataRead::~InformDataRead()
+ {
+ }
+}} //namespace zorba, http_client
=== added file 'modules/io/zorba/modules/http-client.xq.src/inform_data_read.h'
--- modules/io/zorba/modules/http-client.xq.src/inform_data_read.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/inform_data_read.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef INFORM_DATA_READ_H
+#define INFORM_DATA_READ_H
+namespace zorba { namespace http_client {
+ class InformDataRead {
+ public:
+ virtual ~InformDataRead();
+ public:
+ virtual void beforeRead() = 0;
+ virtual void afterRead() = 0;
+ };
+}} //namespace zorba, http_client
+#endif //INFORM_DATA_READ_H
=== added file 'modules/io/zorba/modules/http-client.xq.src/request_handler.cpp'
--- modules/io/zorba/modules/http-client.xq.src/request_handler.cpp 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/request_handler.cpp 2013-06-15 00:58:33 +0000
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "request_handler.h"
+
+namespace zorba { namespace http_client {
+ RequestHandler::~RequestHandler()
+ {
+ }
+}} //namespace zorba, http_client
=== added file 'modules/io/zorba/modules/http-client.xq.src/request_handler.h'
--- modules/io/zorba/modules/http-client.xq.src/request_handler.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/request_handler.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef REQUEST_HANDLER_H
+#define REQUEST_HANDLER_H
+
+#include<string>
+
+namespace zorba {
+class String;
+class Item;
+class ItemSequence;
+
+namespace http_client {
+ class RequestHandler {
+ public:
+ virtual ~RequestHandler();
+ public:
+ virtual void begin() = 0;
+ virtual void beginResponse(int aStatus, String aMessage) = 0;
+ virtual void endResponse() = 0;
+ virtual void beginRequest(
+ String aMethod,
+ String href,
+ bool aStatusOnly,
+ String aUsername,
+ String aPassword,
+ String aAuthMethod,
+ bool aSendAuthorization,
+ String aOverrideContentType,
+ bool aFollowRedirect,
+ String aUserAgent,
+ int aTimeout = -1) = 0;
+ virtual void endRequest() = 0;
+ virtual void header(String aName, String aValue) = 0;
+ virtual void beginBody(
+ String aContentType,
+ String aSrc,
+ ItemSequence* aSerializerOptions) = 0;
+ virtual void any(Item aItem, std::string& charset) = 0;
+ virtual void endBody() = 0;
+ virtual void beginMultipart(String aContentType, String aBoundary) = 0;
+ virtual void endMultipart() = 0;
+ virtual void end() = 0;
+ public: // status
+ virtual bool isHeadRequest() const = 0;
+ };
+}
+}
+
+#endif //REQUEST_HANDLER_H
=== added file 'modules/io/zorba/modules/http-client.xq.src/request_parser.cpp'
--- modules/io/zorba/modules/http-client.xq.src/request_parser.cpp 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/request_parser.cpp 2013-06-15 00:58:33 +0000
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "request_parser.h"
+#include "request_handler.h"
+#include "http_response_parser.h"
+#include "error_thrower.h"
+
+#include <cassert>
+#include <iostream>
+
+#include <zorba/zorba.h>
+#include <zorba/api_shared_types.h>
+#include <zorba/item.h>
+#include <zorba/zorba_string.h>
+#include <zorba/iterator.h>
+#include <zorba/store_consts.h>
+#include <zorba/vector_item_sequence.h>
+#include <zorba/xquery_functions.h>
+#include <zorba/transcode_stream.h>
+
+namespace zorba
+{
+namespace http_client
+{
+
+bool RequestParser::getString(const Item& aItem, const String& aName, const bool aMandatory, String& aResult)
+{
+ Item lOption = aItem.getObjectValue(aName);
+ if (lOption.isNull())
+ {
+ if (aMandatory)
+ raiseMissingError(aName);
+ return false;
+ }
+ else
+ {
+ if (lOption.getTypeCode() != store::XS_STRING &&
+ lOption.getTypeCode() != store::XS_NORMALIZED_STRING &&
+ lOption.getTypeCode() != store::XS_NAME &&
+ lOption.getTypeCode() != store::XS_NCNAME &&
+ lOption.getTypeCode() != store::XS_ANY_URI
+ )
+ raiseTypeError(aName,lOption.getType().getLocalName(), "string");
+ aResult = lOption.getStringValue();
+ return true;
+ }
+}
+
+bool RequestParser::getInteger(const Item& aItem, const String& aName, const bool aMandatory, int& aResult)
+{
+ Item lOption = aItem.getObjectValue(aName);
+ if (lOption.isNull())
+ {
+ if (aMandatory)
+ raiseMissingError(aName);
+ return false;
+ }
+ else
+ {
+ if (lOption.getTypeCode() != store::XS_INTEGER)
+ raiseTypeError(aName,lOption.getType().getLocalName(), "integer");
+ aResult = lOption.getIntValue();
+ return true;
+ }
+}
+
+bool RequestParser::getBoolean(const Item& aItem, const String& aName, const bool aMandatory, bool& aResult)
+{
+ Item lOption = aItem.getObjectValue(aName);
+ if (lOption.isNull())
+ {
+ if (aMandatory)
+ raiseMissingError(aName);
+ return false;
+ }
+ else
+ {
+ if (lOption.getTypeCode() != store::XS_BOOLEAN)
+ raiseTypeError(aName, lOption.getType().getLocalName(), "boolean");
+ aResult = lOption.getBooleanValue();
+ return true;
+ }
+}
+
+bool RequestParser::getObject(const Item& aItem, const String& aName, const bool aMandatory, Item& aResult)
+{
+ aResult = aItem.getObjectValue(aName);
+ if (aResult.isNull())
+ {
+ if (aMandatory)
+ raiseMissingError(aName);
+ return false;
+ }
+ else
+ {
+ if (aResult.isAtomic() || !aResult.isJSONItem() || aResult.getJSONItemKind() != store::StoreConsts::jsonObject)
+ raiseTypeError(aName, aResult.getType().getLocalName(), store::StoreConsts::toString(store::StoreConsts::jsonObject));
+ return true;
+ }
+}
+
+bool RequestParser::getItem(const Item& aItem, const String& aName, const bool aMandatory, Item& aResult)
+{
+ aResult = aItem.getObjectValue(aName);
+ if (aResult.isNull())
+ {
+ if (aMandatory)
+ raiseMissingError(aName);
+ return false;
+ }
+ return true;
+}
+
+bool RequestParser::getArray(const Item& aItem, const String& aName, const bool aMandatory, Item& aResult)
+{
+ aResult = aItem.getObjectValue(aName);
+ if (aResult.isNull())
+ {
+ if (aMandatory)
+ raiseMissingError(aName);
+ return false;
+ }
+ else
+ {
+ if (aResult.isAtomic() || !aResult.isJSONItem() || aResult.getJSONItemKind() != store::StoreConsts::jsonArray)
+ raiseTypeError(aName, store::StoreConsts::toString(aResult.getJSONItemKind()), store::StoreConsts::toString(store::StoreConsts::jsonArray));
+ return true;
+ }
+}
+
+void RequestParser::raiseTypeError(const String& aName, const String& aGot, const String& aExpected)
+{
+ std::ostringstream lMsg;
+ lMsg << aGot << ": invalid type for field "
+ << aName << " (got " << aGot << ", expected " << aExpected << ")";
+ theThrower->raiseException("HC005", lMsg.str());
+}
+
+void RequestParser::raiseMissingError(const String& aName)
+{
+ std::ostringstream lMsg;
+ lMsg << "required field " << aName << " has not been specified";
+ theThrower->raiseException("HC005", lMsg.str());
+}
+
+void RequestParser::parseHeaders(const Item& aItem)
+{
+ Item lKey;
+ String lName;
+ String lValue;
+
+ zorba::Iterator_t lIterator = aItem.getObjectKeys();
+ lIterator->open();
+
+ while (lIterator->next(lKey))
+ {
+ lName = lKey.getStringValue();
+ getString(aItem,lName,true,lValue);
+ theHandler->header(lName, lValue);
+ }
+
+ lIterator->close();
+}
+
+void RequestParser::parseOptions(const Item& aItem, bool& aStatusOnly, String& aOverrideContentType,bool& aFollowRedirect, bool& aUserDefinedFollowRedirect, String& aUserAgent, int& aTimeout)
+{
+ getBoolean(aItem,"status-only",false,aStatusOnly);
+ getString(aItem,"override-media-type", false,aOverrideContentType);
+ aUserDefinedFollowRedirect = getBoolean(aItem,"follow-redirect", false,aFollowRedirect);
+ getInteger(aItem,"timeout",false,aTimeout);
+ getString(aItem,"user-agent",false,aUserAgent);
+}
+
+void RequestParser::parseBody(const Item& aItem)
+{
+ String lMediaType;
+ String lSrc;
+
+ getString(aItem,"media-type",true,lMediaType);
+ std::string charset;
+ getCharset(lMediaType, charset);
+ getString(aItem,"src",false,lSrc);
+
+ std::vector<Item> lItems;
+ std::auto_ptr<VectorItemSequence> lSequence(new VectorItemSequence(lItems));
+ theHandler->beginBody(lMediaType, lSrc, lSequence.get());
+
+ Item lContentI;
+ getItem(aItem,"content",true,lContentI);
+ theHandler->any(lContentI,charset);
+ theHandler->endBody();
+}
+
+void RequestParser::parsePart(const Item& aItem)
+{
+ Item lHeaders;
+ Item lBody;
+
+ bool lHaveHeaders = getObject(aItem,"headers",false,lHeaders);
+ if (lHaveHeaders)
+ parseHeaders(lHeaders);
+
+ getObject(aItem,"body",true,lBody);
+ parseBody(lBody);
+}
+
+void RequestParser::parseMultipart(const Item& aItem)
+{
+ String lMediaType;
+ String lBoundary;
+
+ std::string charset;
+ getString(aItem,"media-type",true,lMediaType);
+ getCharset(lMediaType,charset);
+ getString(aItem,"boundary",false,lBoundary);
+
+ theHandler->beginMultipart(lMediaType, lBoundary);
+ Item lParts = aItem.getObjectValue("parts");
+ if (!lParts.isNull())
+ {
+ if (lParts.isAtomic() || !lParts.isJSONItem() || lParts.getJSONItemKind() != store::StoreConsts::jsonArray)
+ raiseTypeError("parts", store::StoreConsts::toString(lParts.getJSONItemKind()), store::StoreConsts::toString(store::StoreConsts::jsonArray));
+ else
+ {
+ uint64_t lSize = lParts.getArraySize();
+ for(uint64_t i = 1; i <= lSize; ++i)
+ {
+ Item lMember = lParts.getArrayValue(i);
+ if (lMember.isAtomic() || !lMember.isJSONItem() || lMember.getJSONItemKind() != store::StoreConsts::jsonObject)
+ raiseTypeError("part",store::StoreConsts::toString(lMember.getJSONItemKind()),store::StoreConsts::toString(store::StoreConsts::jsonObject));
+ parsePart(lMember);
+ }
+ }
+ }
+ theHandler->endMultipart();
+}
+
+void RequestParser::parseAuthentication(const Item& aItem, String& aUserName, String& aPassword, String& aAuthMethod)
+{
+ getString(aItem,"username",true,aUserName);
+ getString(aItem,"password",true,aPassword);
+ getString(aItem,"auth-method",true,aAuthMethod);
+}
+
+void RequestParser::parseRequest(const Item& aItem)
+{
+ theHandler->begin();
+ String lMethod;
+ String lHref;
+ bool lStatusOnly = false;
+ String lUsername;
+ String lPassword;
+ String lAuthMethod;
+ bool lSendAuthentication = false;
+ String lOverrideContentType;
+ bool lFollowRedirect = false;
+ bool lUserDefinedFollowRedirect = false;
+ int lTimeout = -1;
+ String lUserAgent;
+
+ if(!getString(aItem,"method",false,lMethod))
+ lMethod ="GET";
+ getString(aItem,"href",true,lHref);
+
+ Item lAuthentication;
+ if ((lSendAuthentication = getObject(aItem,"authentication",false,lAuthentication)))
+ parseAuthentication(lAuthentication,lUsername,lPassword,lAuthMethod);
+
+ Item lOptions;
+ if (getObject(aItem,"options",false,lOptions))
+ parseOptions(lOptions,lStatusOnly,lOverrideContentType,lFollowRedirect,lUserDefinedFollowRedirect,lUserAgent,lTimeout);
+
+ lMethod = fn::upper_case(lMethod);
+
+ // follow-redirect: take care of the default (if the user didn't provide one)
+ if (lMethod == "GET" || lMethod == "HEAD" || lMethod == "OPTIONS")
+ {
+ if (!lUserDefinedFollowRedirect)
+ lFollowRedirect = "true";
+ }
+ else
+ {
+ if (lFollowRedirect)
+ {
+ std::ostringstream lMsg;
+ lMsg << lMethod << ": cannot follow redirect";
+ theThrower->raiseException("HCV02", lMsg.str());
+ }
+ }
+
+ theHandler->beginRequest(lMethod, lHref, lStatusOnly, lUsername, lPassword,
+ lAuthMethod, lSendAuthentication, lOverrideContentType, lFollowRedirect,
+ lUserAgent, lTimeout);
+
+ Item lHeaders;
+ bool haveHeaders = getObject(aItem,"headers",false,lHeaders);
+ if (haveHeaders)
+ parseHeaders(lHeaders);
+
+ Item lBody;
+ Item lMultipart;
+ bool haveBody = getObject(aItem,"body",false,lBody);
+ bool haveMultipart = getObject(aItem,"multipart",false,lMultipart);
+ if (haveBody && haveMultipart)
+ theThrower->raiseException("HC005","HTTP request cannot contain both body and multipart");
+
+ if (haveBody)
+ parseBody(lBody);
+
+ if (haveMultipart)
+ parseMultipart(lMultipart);
+
+ theHandler->endRequest();
+ theHandler->end();
+}
+
+void RequestParser::getCharset(const String& aMediaType, std::string& charset)
+{
+ std::string mime_type;
+ parse_content_type(aMediaType.c_str(),&mime_type,&charset);
+ if (!charset.empty() && transcode::is_necessary(charset.c_str()) && !transcode::is_supported(charset.c_str()))
+ {
+ std::ostringstream lMsg;
+ lMsg << charset << ": unsupported encoding charset";
+ theThrower->raiseException("HCV03", lMsg.str());
+ }
+}
+
+}
+}
=== added file 'modules/io/zorba/modules/http-client.xq.src/request_parser.h'
--- modules/io/zorba/modules/http-client.xq.src/request_parser.h 1970-01-01 00:00:00 +0000
+++ modules/io/zorba/modules/http-client.xq.src/request_parser.h 2013-06-15 00:58:33 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2006-2013 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef REQUEST_PARSER_H
+#define REQUEST_PARSER_H
+
+#include <string>
+
+namespace zorba {
+class Item;
+class String;
+class ItemFactory;
+
+namespace http_client {
+class RequestHandler;
+class ErrorThrower;
+
+class RequestParser {
+protected:
+ RequestHandler* theHandler;
+ ErrorThrower* theThrower;
+ ItemFactory* theFactory;
+
+public:
+ RequestParser(RequestHandler* aHandler, ErrorThrower& aThrower, ItemFactory* aFactory) : theHandler(aHandler), theThrower(&aThrower), theFactory(aFactory) {}
+ void parseRequest(const Item& aItem);
+
+private:
+ void parseHeaders(const Item& aItem);
+ void parseOptions(const Item& aItem, bool& aStatusOnly, String& aOverrideContentType,bool& aFollowRedirect, bool& aUserDefinedFollowRedirect, String& aUserAgent, int& aTimeout);
+ void parseBody(const Item& aItem);
+ void parsePart(const Item& aItem);
+ void parseMultipart(const Item& aItem);
+ void parseAuthentication(const Item& aItem, String& aUserName, String& aPassword, String& aAuthMethod);
+
+ bool getString(const Item& aItem, const String& aName, const bool aMandatory, String& aResult);
+ bool getInteger(const Item& aItem, const String& aName, const bool aMandatory, int& aResult);
+ bool getBoolean(const Item& aItem, const String& aName, const bool aMandatory, bool& aResult);
+ bool getObject(const Item& aItem, const String& aName, const bool aMandatory, Item& aResult);
+ bool getItem(const Item& aItem, const String& aName, const bool aMandatory, Item& aResult);
+ bool getArray(const Item& aItem, const String& aName, const bool aMandatory, Item& aResult);
+
+ void getCharset(const String& aMediaType, std::string& charset);
+
+ void raiseTypeError(const String& aName, const String& aGot, const String& aExpected);
+ void raiseMissingError(const String& aName);
+};
+} //namespace zorba
+} //namespace http_request
+
+#endif // REQUEST_PARSER_H
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client'
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client/delete'
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/delete/delete.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/delete/delete.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/delete/delete.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+Method: DELETE
+Query:
+Post:
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client/get'
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary'
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_binary.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_binary.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+VW5jaGFuZ2luZyBiaW5hcnkgZGF0YQo=
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_text.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_text.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_text.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+TWV0aG9kOiBHRVQKUXVlcnk6IApQb3N0OiAK
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_text_query.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_text_query.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_text_query.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+TWV0aG9kOiBHRVQKUXVlcnk6IHF1ZXJ5c3RyaW5nClBvc3Q6IAo=
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_xml.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_xml.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_xml.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+PGJvZHk+CjxtZXRob2Q+R0VUPC9tZXRob2Q+CjxxdWVyeT48L3F1ZXJ5Pgo8cG9zdD4KPC9wb3N0PjwvYm9keT4K
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_xml_query.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_xml_query.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-binary/get-binary_xml_query.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+PGJvZHk+CjxtZXRob2Q+R0VUPC9tZXRob2Q+CjxxdWVyeT5xdWVyeXN0cmluZzwvcXVlcnk+Cjxwb3N0Pgo8L3Bvc3Q+PC9ib2R5Pgo=
\ No newline at end of file
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-node'
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_binary.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_binary.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+VW5jaGFuZ2luZyBiaW5hcnkgZGF0YQo=
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_text.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_text.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_text.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+Method: GET
+Query:
+Post:
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_text_query.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_text_query.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_text_query.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+Method: GET
+Query: querystring
+Post:
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_xml.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_xml.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_xml.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+<body>
+<method>GET</method>
+<query/>
+<post>
+</post></body>
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_xml_query.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_xml_query.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-node/get-node_xml_query.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+querystring
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-text'
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_binary.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_binary.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Unchanging binary data
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_text.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_text.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_text.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+Method: GET
+Query:
+Post:
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_text_query.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_text_query.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_text_query.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+Method: GET
+Query: querystring
+Post:
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_xml.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_xml.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_xml.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+<body>
+<method>GET</method>
+<query></query>
+<post>
+</post></body>
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_xml_query.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_xml_query.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get-text/get-text_xml_query.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+<body>
+<method>GET</method>
+<query>querystring</query>
+<post>
+</post></body>
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_binary.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_binary.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+VW5jaGFuZ2luZyBiaW5hcnkgZGF0YQo=
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_text.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_text.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_text.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+Method: GET
+Query:
+Post:
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_text_query.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_text_query.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_text_query.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+Method: GET
+Query: querystring
+Post:
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_xml.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_xml.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_xml.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+<body>
+<method>GET</method>
+<query/>
+<post>
+</post></body>
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_xml_query.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_xml_query.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/get/get_xml_query.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+querystring
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client/head'
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_content-type_binary.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_content-type_binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_content-type_binary.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+application/octet-stream
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_content-type_text.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_content-type_text.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_content-type_text.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+text/plain; charset=UTF-8
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_content-type_xml.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_content-type_xml.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_content-type_xml.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+text/xml
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_status.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_status.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/head/head_status.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+200
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client/options'
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/options/options.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/options/options.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/options/options.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+GET HEAD POST OPTIONS TRACE
\ No newline at end of file
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client/post'
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/post/post2_binary.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/post/post2_binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/post/post2_binary.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+Method: POST
+Query:
+Post:
+hello there
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/post/post2_string.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/post/post2_string.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/post/post2_string.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+Method: POST
+Query:
+Post:
+poststring
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/post/post3_binary.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/post/post3_binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/post/post3_binary.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+Method: POST
+Query:
+Post:
+hello there
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/post/post3_string.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/post/post3_string.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/post/post3_string.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+Method: POST
+Query:
+Post:
+poststring
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client/put'
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/put/put2_binary.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/put/put2_binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/put/put2_binary.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+Method: PUT
+Query:
+Post:
+hello there
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/put/put2_string.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/put/put2_string.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/put/put2_string.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+Method: PUT
+Query:
+Post:
+putstring
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/put/put3_binary.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/put/put3_binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/put/put3_binary.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+Method: PUT
+Query:
+Post:
+hello there
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/put/put3_string.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/put/put3_string.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/put/put3_string.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+Method: PUT
+Query:
+Post:
+putstring
\ No newline at end of file
=== added directory 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request'
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http1-redirect.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http1-redirect.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http1-redirect.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+200
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http1-useragent.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http1-useragent.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http1-useragent.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+28.io
\ No newline at end of file
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http2-read-svg.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http2-read-svg.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http2-read-svg.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink"; xmlns:ev="http://www.w3.org/2001/xml-events"; version="1.1" baseProfile="full" width="700px" height="400px" viewBox="0 0 700 400">
+
+ <!-- Anschlüsse links und rechts -->
+ <line x1="0" y1="200" x2="700" y2="200" stroke="black" stroke-width="20px"/>
+ <!-- Das Rechteck -->
+ <rect x="100" y="100" width="500" height="200" fill="white" stroke="black" stroke-width="20px"/>
+ <!-- Der Schleifer -->
+ <line x1="180" y1="370" x2="500" y2="50" stroke="black" stroke-width="15px"/>
+ <!-- Die Pfeilspitze -->
+ <polygon points="585 0 525 25 585 50" transform="rotate(135 525 25)"/>
+</svg>
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http3-multipart.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http3-multipart.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http3-multipart.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+<result><number-of-bodies>3</number-of-bodies><headers><http:header xmlns:http="http://expath.org/ns/http-client"; name="User-Agent" value="libcurl-agent/1.0"/><http:header xmlns:http="http://expath.org/ns/http-client"; name="Host" value="zorbatest.lambda.nu:8080"/><http:header xmlns:http="http://expath.org/ns/http-client"; name="Accept" value="*/*"/><http:header xmlns:http="http://expath.org/ns/http-client"; name="foo" value="bar"/><http:header xmlns:http="http://expath.org/ns/http-client"; name="Expect" value="100-continue"/><http:header xmlns:http="http://expath.org/ns/http-client"; name="Content-Disposition" value="form-data; name="zorba-default""/><http:header xmlns:http="http://expath.org/ns/http-client"; name="insidemutlipart" value="blubb"/><http:header xmlns:http="http://expath.org/ns/http-client"; name="Content-Type" value="text/plain"/><http:header xmlns:http="http://expath.org/ns/http-client"; name="Content-Disposition" value="form-data; name="zorba-default""/><http:header xmlns:http="http://expath.org/ns/http-client"; name="Content-Type" value="text/plain"/><http:header xmlns:http="http://expath.org/ns/http-client"; name="Content-Disposition" value="form-data; name="zorba-default""/><http:header xmlns:http="http://expath.org/ns/http-client"; name="Content-Type" value="img/png"/></headers></result>
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http3-post.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http3-post.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http3-post.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,12 @@
+<http:request xmlns:http="http://expath.org/ns/http-client"; method="POST" href="zorbatest.lambda.nu:8080/http-test-data/request.php">
+ <http:header name="User-Agent" value="libcurl-agent/1.0"/>
+ <http:header name="Host" value="zorbatest.lambda.nu:8080"/>
+ <http:header name="Accept" value="*/*"/>
+ <http:header name="foo" value="bar"/>
+ <http:header name="Content-Type" value="text/plain"/>
+ <http:header name="Content-Length" value="37"/>
+ <http:body content-type="text/plain">
+
+ Dies ist ein kleiner Test
+ </http:body>
+</http:request>
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http_error_hc002.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http_error_hc002.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http_error_hc002.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+ok
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http_error_hc004.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http_error_hc004.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http_error_hc004.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+ok
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http_error_hc005.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http_error_hc005.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/http_error_hc005.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+ok ok ok ok ok ok ok
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/send-request_get_binary.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/send-request_get_binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/send-request_get_binary.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+true true true
=== added file 'test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/send-request_href.xml.res'
--- test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/send-request_href.xml.res 1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/json-http-client/send-request/send-request_href.xml.res 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+<body>
+<method>GET</method>
+<query>querystring</query>
+<post>
+</post></body>
=== added directory 'test/rbkt/Queries/zorba/json-http-client'
=== added directory 'test/rbkt/Queries/zorba/json-http-client/delete'
=== added file 'test/rbkt/Queries/zorba/json-http-client/delete/delete.xq'
--- test/rbkt/Queries/zorba/json-http-client/delete/delete.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/delete/delete.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,7 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $result :=
+ http:delete("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";);
+
+$result.body.content
=== added file 'test/rbkt/Queries/zorba/json-http-client/delete/delete_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/delete/delete_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/delete/delete_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/delete/delete_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/delete/delete_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/delete/delete_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,6 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $result :=
+ http:delete("http://localhost:99558/cgi-bin/test-text";);
+
+$result[2]
=== added directory 'test/rbkt/Queries/zorba/json-http-client/get'
=== added directory 'test/rbkt/Queries/zorba/json-http-client/get-binary'
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_binary.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_binary.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_binary.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get-binary("http://zorbatest.lambda.nu:8080/cgi-bin/test-binary";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+(: Connect to an invalid server :)
+http:get-binary("http://localhost:9998/cgi-bin/test-xml?foo&";)[2]
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_text.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_text.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_text.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get-binary("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_text_query.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_text_query.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_text_query.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get-binary("http://zorbatest.lambda.nu:8080/cgi-bin/test-text?querystring";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_xml.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_xml.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_xml.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get-binary("http://zorbatest.lambda.nu:8080/cgi-bin/test-xml";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_xml_query.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_xml_query.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-binary/get-binary_xml_query.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get-binary("http://zorbatest.lambda.nu:8080/cgi-bin/test-xml?querystring";).body.content
+
=== added directory 'test/rbkt/Queries/zorba/json-http-client/get-node'
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-node/get-node_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/get-node/get-node_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-node/get-node_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-node/get-node_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-node/get-node_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-node/get-node_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,6 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+(: Connect to an invalid server :)
+http:get("http://localhost:9998/cgi-bin/test-xml?foo&";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-node/get-node_xml.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-node/get-node_xml.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-node/get-node_xml.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+parse-xml(http:get("http://zorbatest.lambda.nu:8080/cgi-bin/test-xml";)("body")("content"))
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-node/get-node_xml_query.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-node/get-node_xml_query.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-node/get-node_xml_query.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+parse-xml(http:get("http://zorbatest.lambda.nu:8080/cgi-bin/test-xml?querystring";)("body")("content"))/body/query/text()
+
=== added directory 'test/rbkt/Queries/zorba/json-http-client/get-text'
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-text/get-text_binary.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-text/get-text_binary.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-text/get-text_binary.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get-text("http://zorbatest.lambda.nu:8080/cgi-bin/test-binary";).body.content
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-text/get-text_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/get-text/get-text_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-text/get-text_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-text/get-text_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-text/get-text_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-text/get-text_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+(: Connect to an invalid server :)
+http:get-text("http://localhost:9998/cgi-bin/test-xml?foo&";)[2]
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-text/get-text_text.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-text/get-text_text.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-text/get-text_text.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get-text("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-text/get-text_text_query.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-text/get-text_text_query.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-text/get-text_text_query.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get-text("http://zorbatest.lambda.nu:8080/cgi-bin/test-text?querystring";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-text/get-text_xml.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-text/get-text_xml.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-text/get-text_xml.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get-text("http://zorbatest.lambda.nu:8080/cgi-bin/test-xml";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get-text/get-text_xml_query.xq'
--- test/rbkt/Queries/zorba/json-http-client/get-text/get-text_xml_query.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get-text/get-text_xml_query.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get-text("http://zorbatest.lambda.nu:8080/cgi-bin/test-xml?querystring";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get/get_binary.xq'
--- test/rbkt/Queries/zorba/json-http-client/get/get_binary.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get/get_binary.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get("http://zorbatest.lambda.nu:8080/cgi-bin/test-binary";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get/get_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/get/get_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get/get_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/get/get_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/get/get_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get/get_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+(: Connect to an invalid server :)
+http:get("http://localhost:9998/cgi-bin/test-xml?foo&";)[2]
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get/get_text.xq'
--- test/rbkt/Queries/zorba/json-http-client/get/get_text.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get/get_text.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get/get_text_query.xq'
--- test/rbkt/Queries/zorba/json-http-client/get/get_text_query.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get/get_text_query.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,5 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+http:get("http://zorbatest.lambda.nu:8080/cgi-bin/test-text?querystring";).body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/get/get_xml.xq'
--- test/rbkt/Queries/zorba/json-http-client/get/get_xml.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get/get_xml.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,4 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+parse-xml(http:get("http://zorbatest.lambda.nu:8080/cgi-bin/test-xml";).body.content)
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/get/get_xml_query.xq'
--- test/rbkt/Queries/zorba/json-http-client/get/get_xml_query.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/get/get_xml_query.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+parse-xml(http:get("http://zorbatest.lambda.nu:8080/cgi-bin/test-xml?querystring";)("body")("content"))/body/query/text()
=== added directory 'test/rbkt/Queries/zorba/json-http-client/head'
=== added file 'test/rbkt/Queries/zorba/json-http-client/head/head_content-type_binary.xq'
--- test/rbkt/Queries/zorba/json-http-client/head/head_content-type_binary.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/head/head_content-type_binary.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,6 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+declare namespace exp="http://expath.org/ns/http-client";;
+
+http:head("http://zorbatest.lambda.nu:8080/cgi-bin/test-binary";).headers.("Content-Type")
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/head/head_content-type_text.xq'
--- test/rbkt/Queries/zorba/json-http-client/head/head_content-type_text.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/head/head_content-type_text.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,6 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+declare namespace exp="http://expath.org/ns/http-client";;
+
+http:head("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";).headers("Content-Type")
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/head/head_content-type_xml.xq'
--- test/rbkt/Queries/zorba/json-http-client/head/head_content-type_xml.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/head/head_content-type_xml.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,6 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+declare namespace exp="http://expath.org/ns/http-client";;
+
+http:head("http://zorbatest.lambda.nu:8080/cgi-bin/test-xml";).headers("Content-Type")
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/head/head_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/head/head_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/head/head_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/head/head_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/head/head_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/head/head_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,9 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+declare namespace exp="http://expath.org/ns/http-client";;
+
+data(
+ http:head("http://localhost:99955/cgi-bin/test-xml";)/@status
+)
+
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/head/head_status.xq'
--- test/rbkt/Queries/zorba/json-http-client/head/head_status.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/head/head_status.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,6 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+declare namespace exp="http://expath.org/ns/http-client";;
+
+http:head("http://zorbatest.lambda.nu:8080/cgi-bin/test-xml";).status
\ No newline at end of file
=== added directory 'test/rbkt/Queries/zorba/json-http-client/options'
=== added file 'test/rbkt/Queries/zorba/json-http-client/options/options.xq'
--- test/rbkt/Queries/zorba/json-http-client/options/options.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/options/options.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+import module namespace http = "http://zorba.io/modules/http-client";;
+http:options("http://zorbatest.lambda.nu:8080/http-test-data/http1.xml";)
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/options/options_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/options/options_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/options/options_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/options/options_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/options/options_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/options/options_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,3 @@
+import module namespace http = "http://zorba.io/modules/http-client";;
+http:options("http://localhost:99558/rest-tests/http1.xml";)
+
=== added directory 'test/rbkt/Queries/zorba/json-http-client/post'
=== added file 'test/rbkt/Queries/zorba/json-http-client/post/post2_binary.xq'
--- test/rbkt/Queries/zorba/json-http-client/post/post2_binary.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/post/post2_binary.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,10 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+(: value is "hello there" in base64 :)
+variable $arg as xs:base64Binary := "aGVsbG8gdGhlcmUK" cast as xs:base64Binary;
+variable $result :=
+ http:post("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";, $arg);
+
+$result.body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/post/post2_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/post/post2_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/post/post2_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/post/post2_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/post/post2_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/post/post2_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,8 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $arg := "hello";
+variable $result :=
+ http:post("http://localhost:99558/cgi-bin/test-text";, $arg);
+
+$result[2]
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/post/post2_string.xq'
--- test/rbkt/Queries/zorba/json-http-client/post/post2_string.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/post/post2_string.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,6 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $result := http:post("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";, "poststring");
+
+$result.body.content
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/post/post3_binary.xq'
--- test/rbkt/Queries/zorba/json-http-client/post/post3_binary.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/post/post3_binary.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,9 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+(: value is "hello there" in base64 :)
+variable $arg as xs:base64Binary := "aGVsbG8gdGhlcmUK" cast as xs:base64Binary;
+variable $result := http:post("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";, $arg, "application/octet-stream");
+
+$result.body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/post/post3_encoding_error.spec'
--- test/rbkt/Queries/zorba/json-http-client/post/post3_encoding_error.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/post/post3_encoding_error.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HCV03
=== added file 'test/rbkt/Queries/zorba/json-http-client/post/post3_encoding_error.xq'
--- test/rbkt/Queries/zorba/json-http-client/post/post3_encoding_error.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/post/post3_encoding_error.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,7 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $arg := "hello";
+variable $result := http:post("http://localhost:99558/cgi-bin/test-text";, $arg, "text plain; charset=mycharset");
+
+$result[2]
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/post/post3_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/post/post3_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/post/post3_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/post/post3_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/post/post3_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/post/post3_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,9 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $arg := "hello";
+variable $result :=
+ http:post("http://localhost:99558/cgi-bin/test-text";, $arg,
+ "application/octet-stream");
+
+$result[2]
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/post/post3_string.xq'
--- test/rbkt/Queries/zorba/json-http-client/post/post3_string.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/post/post3_string.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,6 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $result := http:post("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";, "poststring","text/plain");
+$result.body.content
+
=== added directory 'test/rbkt/Queries/zorba/json-http-client/put'
=== added file 'test/rbkt/Queries/zorba/json-http-client/put/put2_binary.xq'
--- test/rbkt/Queries/zorba/json-http-client/put/put2_binary.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/put/put2_binary.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,10 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+(: value is "hello there" in base64 :)
+variable $arg as xs:base64Binary := "aGVsbG8gdGhlcmUK" cast as xs:base64Binary;
+variable $result :=
+ http:put("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";, $arg);
+
+$result.body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/put/put2_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/put/put2_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/put/put2_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/put/put2_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/put/put2_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/put/put2_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,8 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $arg := "hello";
+variable $result :=
+ http:put("http://localhost:99558/cgi-bin/test-text";, $arg);
+
+$result[2]
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/put/put2_string.xq'
--- test/rbkt/Queries/zorba/json-http-client/put/put2_string.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/put/put2_string.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,8 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $result :=
+ http:put("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";, "putstring");
+
+$result.body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/put/put3_binary.xq'
--- test/rbkt/Queries/zorba/json-http-client/put/put3_binary.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/put/put3_binary.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,9 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+(: value is "hello there" in base64 :)
+variable $arg as xs:base64Binary := "aGVsbG8gdGhlcmUK" cast as xs:base64Binary;
+variable $result := http:put("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";, $arg, "application/octet-stream");
+
+$result.body.content
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/put/put3_error_http.spec'
--- test/rbkt/Queries/zorba/json-http-client/put/put3_error_http.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/put/put3_error_http.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HC001
=== added file 'test/rbkt/Queries/zorba/json-http-client/put/put3_error_http.xq'
--- test/rbkt/Queries/zorba/json-http-client/put/put3_error_http.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/put/put3_error_http.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,9 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $arg := "hello";
+variable $result :=
+ http:put("http://localhost:99558/cgi-bin/test-text";, $arg,
+ "application/octet-stream");
+
+$result[2]
+
=== added file 'test/rbkt/Queries/zorba/json-http-client/put/put3_string.xq'
--- test/rbkt/Queries/zorba/json-http-client/put/put3_string.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/put/put3_string.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,7 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $result :=
+ http:put("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";, "putstring","text/plain");
+
+$result.body.content
\ No newline at end of file
=== added directory 'test/rbkt/Queries/zorba/json-http-client/send-request'
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/http1-redirect.xq'
--- test/rbkt/Queries/zorba/json-http-client/send-request/http1-redirect.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/http1-redirect.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,32 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+declare namespace h = "http://expath.org/ns/http-client";;
+
+variable $http-res-with :=
+http:send-request(
+{
+ "href": "http://zorbatest.lambda.nu:8080/remotequeue";,
+ "method": "HEAD",
+ "options": {
+ "follow-redirect": true
+ }
+});
+
+variable $http-res-without :=
+http:send-request(
+{
+ "href": "http://zorbatest.lambda.nu:8080/remotequeue";,
+ "method": "HEAD",
+ "options": {
+ "follow-redirect": false
+ }
+});
+
+let $status-with := $http-res-with.status
+let $status-without := $http-res-without.status
+return
+ if ($status-without eq 301) then
+ $status-with
+ else "failed"
+
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/http1-useragent.xq'
--- test/rbkt/Queries/zorba/json-http-client/send-request/http1-useragent.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/http1-useragent.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,18 @@
+import module namespace http="http://zorba.io/modules/http-client";;
+
+variable $req :=
+{
+ "method": "POST",
+ "href": "http://zorbatest.lambda.nu:8080/http-test-data/request.php";,
+ "body": {
+ "media-type": "text/plain",
+ "content": "
+ Dies ist ein kleiner Test
+ "
+ },
+ "options": {
+ "user-agent": "28.io"
+ }
+};
+
+parse-xml(http:send-request($req)("body")("content"))//*:header[@*:name="User-Agent"]/@value/string(.)
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/http2-read-svg.xq'
--- test/rbkt/Queries/zorba/json-http-client/send-request/http2-read-svg.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/http2-read-svg.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,20 @@
+jsoniq version "1.0";
+(: test content having a content type ending with +xml, i.e. image/svg+xml :)
+import module namespace http = "http://zorba.io/modules/http-client";;
+declare namespace h = "http://expath.org/ns/http-client";;
+
+variable $req :=
+{
+ "method": "GET",
+ "href": "http://zorbatest.lambda.nu:8080/http-test-data/basic-auth/example.svg";,
+ "authentication": {
+ "auth-method": "Basic",
+ "username": "zorba",
+ "password": "blub"
+ },
+ "options": {
+ "override-media-type": "application/xml; charset=utf-8"
+ }
+};
+
+parse-xml(http:send-request($req).body.content)
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/http3-multipart.xq'
--- test/rbkt/Queries/zorba/json-http-client/send-request/http3-multipart.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/http3-multipart.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,52 @@
+xquery version "3.0";
+import module namespace httpc = "http://zorba.io/modules/http-client";;
+import module namespace libjn = "http://jsoniq.org/function-library";;
+
+declare namespace http = "http://expath.org/ns/http-client";;
+
+variable $req :=
+{
+ "method": "POST",
+ "href": "http://zorbatest.lambda.nu:8080/http-test-data/request.php";,
+ "headers": {"foo": "bar"},
+ "multipart": {
+ "media-type": "multipart/mixed",
+ "parts" : [
+ {
+ "headers": {"insidemutlipart": "blubb"},
+ "body": {
+ "media-type": "text/plain",
+ "content": "
+ A small text test
+ "
+ }
+ },
+ {
+ "body": {
+ "media-type": "text/plain",
+ "content": "
+ Another small text body
+ "
+ }
+ },
+ {
+ "body": {
+ "media-type": "img/png",
+ "content": "lqenw"
+ }
+ }
+ ]
+ }
+};
+
+variable $res := parse-xml(httpc:send-request($req)("body")("content"));
+<result>
+ <number-of-bodies>{fn:count($res//http:body)}</number-of-bodies>
+ <headers>{
+ $res//http:header[fn:not(
+ fn:contains(data(@value), "boundary")
+ or
+ fn:contains(data(@name), "------")
+ or
+ fn:contains(data(@name), "Content-Length"))]}</headers>
+</result>
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/http3-post.xq'
--- test/rbkt/Queries/zorba/json-http-client/send-request/http3-post.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/http3-post.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,19 @@
+jsoniq version "1.0";
+import module namespace http = "http://zorba.io/modules/http-client";;
+
+declare default element namespace "http://expath.org/ns/http-client";;
+
+variable $req :=
+{
+ "method": "POST",
+ "href": "http://zorbatest.lambda.nu:8080/http-test-data/request.php";,
+ "headers": {"foo":"bar"},
+ "body": {
+ "media-type": "text/plain",
+ "content": "
+ Dies ist ein kleiner Test
+ "
+ }
+};
+
+parse-xml(http:send-request($req).body.content)
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/http4-post-redirect.spec'
--- test/rbkt/Queries/zorba/json-http-client/send-request/http4-post-redirect.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/http4-post-redirect.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/modules/http-client:HCV02
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/http4-post-redirect.xq'
--- test/rbkt/Queries/zorba/json-http-client/send-request/http4-post-redirect.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/http4-post-redirect.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,13 @@
+jsoniq version "1.0";
+import module namespace http="http://zorba.io/modules/http-client";;
+
+declare namespace h = "http://expath.org/ns/http-client";;
+
+http:send-request(
+{
+ "href": "http://zorbatest.lambda.nu:8080/remotequeue";,
+ "method": "POST",
+ "options": {
+ "follow-redirect": true
+ }
+});
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/http_error_hc005.spec'
--- test/rbkt/Queries/zorba/json-http-client/send-request/http_error_hc005.spec 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/http_error_hc005.spec 2013-06-15 00:58:33 +0000
@@ -0,0 +1,1 @@
+ Error: http://www.zorba.io/modules/http-client:HC005
\ No newline at end of file
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/http_error_hc005.xq'
--- test/rbkt/Queries/zorba/json-http-client/send-request/http_error_hc005.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/http_error_hc005.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,65 @@
+import module namespace http = "http://zorba.io/modules/http-client";;
+declare namespace h = "http://expath.org/ns/http-client";;
+
+try {
+ http:send-request({"hi":"hello"})
+} catch http:HC005 {
+ "ok"
+},
+try {
+ http:send-request({"method": 3})
+} catch http:HC005 {
+ "ok"
+},
+try {
+ http:send-request({
+ "mistypedhref": "http://zorbatest.lambda.nu:8080/remotequeue";,
+ "method": "GET",
+ "options": {
+ "follow-redirect": false
+ }
+})
+} catch http:HC005 {
+ "ok"
+},
+try {
+ http:send-request({
+ "href": "http://zorbatest.lambda.nu:8080/remotequeue";,
+ "method": 3,
+ "options": {
+ "follow-redirect": false
+ }
+})
+} catch http:HC005 {
+ "ok"
+},
+try {
+ http:send-request({
+ "href": "http://zorbatest.lambda.nu:8080/remotequeue";,
+ "method": "GET",
+ "headers": "three",
+ "options": {
+ "follow-redirect": false
+ }
+})
+} catch http:HC005 {
+ "ok"
+},
+try {
+ http:post("http://zorbatest.lambda.nu:8080/cgi-bin/test-text";, 3,"text/plain")
+} catch http:HCV04 {
+ "ok"
+},
+try {
+ http:send-request(
+ {
+ "method": "POST",
+ "href": "www.ggg.ggg",
+ "body": {
+ "media-type": "text/plain",
+ "content": [2,3]
+ }
+ })
+} catch http:HCV04 {
+ "ok"
+}
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/send-request_get_binary.xq'
--- test/rbkt/Queries/zorba/json-http-client/send-request/send-request_get_binary.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/send-request_get_binary.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,22 @@
+jsoniq version "1.0";
+import module namespace http = "http://zorba.io/modules/http-client";;
+declare namespace h = "http://expath.org/ns/http-client";;
+
+variable $req :=
+{
+ "method": "GET",
+ "href": "http://zorbatest.lambda.nu:8080/http-test-data/basic-auth/download.png";,
+ "authentication": {
+ "auth-method": "Basic",
+ "username": "zorba",
+ "password": "blub"
+ }
+};
+
+let $res := http:send-request($req)
+return
+(
+ $res.headers.("Content-Type") eq "image/png",
+ $res.body.("media-type") eq "image/png",
+ $res.headers.("Content-Length") eq "5577"
+)
=== added file 'test/rbkt/Queries/zorba/json-http-client/send-request/send-request_href.xq'
--- test/rbkt/Queries/zorba/json-http-client/send-request/send-request_href.xq 1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/json-http-client/send-request/send-request_href.xq 2013-06-15 00:58:33 +0000
@@ -0,0 +1,10 @@
+jsoniq version "1.0";
+import module namespace http = "http://zorba.io/modules/http-client";;
+
+variable $req :=
+{
+ "method" : "GET",
+ "href" : "http://zorbatest.lambda.nu:8080/cgi-bin/test-xml?querystring";
+};
+
+parse-xml(http:send-request($req).body.content)
\ No newline at end of file
Follow ups
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: noreply, 2013-07-25
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-25
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-25
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-25
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Federico Cavalieri, 2013-07-25
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-25
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-25
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-24
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-24
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Federico Cavalieri, 2013-07-24
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Federico Cavalieri, 2013-07-24
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-24
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-24
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-24
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-24
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Federico Cavalieri, 2013-07-24
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-24
-
[Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Zorba Build Bot, 2013-07-24
-
Re: [Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Chris Hillery, 2013-07-24
-
Re: [Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Federico Cavalieri, 2013-07-19
-
Re: [Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Chris Hillery, 2013-07-09
-
Re: [Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Cezar Andrei, 2013-06-24
-
Re: [Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Federico Cavalieri, 2013-06-21
-
Re: [Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Chris Hillery, 2013-06-21
-
Re: [Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Cezar Andrei, 2013-06-19
-
Re: [Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Cezar Andrei, 2013-06-19
-
Re: [Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Cezar Andrei, 2013-06-19
-
Re: [Merge] lp:~zorba-coders/zorba/json-http-module into lp:zorba
From: Cezar Andrei, 2013-06-18