Merge lp:~zorba-coders/zorba/json-http-module into lp:zorba

Proposed by Federico Cavalieri on 2013-06-15
Status: Merged
Approved by: Federico Cavalieri on 2013-07-24
Approved revision: 11529
Merged at revision: 11564
Proposed branch: lp:~zorba-coders/zorba/json-http-module
Merge into: lp:zorba
Diff against target: 9158 lines (+5250/-2729)
176 files modified
include/zorba/item.h (+15/-0)
include/zorba/util/hexbinary_util.h (+51/-0)
modules/CMakeLists.txt (+1/-0)
modules/com/zorba-xquery/www/modules/CMakeLists.txt (+0/-39)
modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_overwrite.h (+0/-23)
modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_redefines.h (+0/-30)
modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_stream_buffer.cpp (+0/-379)
modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_stream_buffer.h (+0/-193)
modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_wrappers.h (+0/-45)
modules/com/zorba-xquery/www/modules/http-client.xq.src/error_thrower.h (+0/-53)
modules/com/zorba-xquery/www/modules/http-client.xq.src/http_client.cpp (+0/-256)
modules/com/zorba-xquery/www/modules/http-client.xq.src/http_request_handler.cpp (+0/-292)
modules/com/zorba-xquery/www/modules/http-client.xq.src/http_request_handler.h (+0/-113)
modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_handler.cpp (+0/-232)
modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_handler.h (+0/-115)
modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_parser.cpp (+0/-351)
modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_parser.h (+0/-92)
modules/com/zorba-xquery/www/modules/http-client.xq.src/inform_data_read.cpp (+0/-22)
modules/com/zorba-xquery/www/modules/http-client.xq.src/inform_data_read.h (+0/-27)
modules/com/zorba-xquery/www/modules/http-client.xq.src/request_handler.cpp (+0/-22)
modules/com/zorba-xquery/www/modules/http-client.xq.src/request_handler.h (+0/-60)
modules/com/zorba-xquery/www/modules/http-client.xq.src/request_parser.cpp (+0/-276)
modules/com/zorba-xquery/www/modules/http-client.xq.src/request_parser.h (+0/-46)
modules/http-client/CMakeLists.txt (+60/-0)
modules/http-client/json/http-client.jsd (+215/-0)
modules/http-client/json/http-client.xq (+692/-0)
modules/http-client/json/http-client.xq.src/curl_stream_buffer.cpp (+379/-0)
modules/http-client/json/http-client.xq.src/curl_stream_buffer.h (+193/-0)
modules/http-client/json/http-client.xq.src/error_thrower.h (+66/-0)
modules/http-client/json/http-client.xq.src/http_client.cpp (+255/-0)
modules/http-client/json/http-client.xq.src/http_request_handler.cpp (+469/-0)
modules/http-client/json/http-client.xq.src/http_request_handler.h (+119/-0)
modules/http-client/json/http-client.xq.src/http_response_handler.cpp (+294/-0)
modules/http-client/json/http-client.xq.src/http_response_handler.h (+126/-0)
modules/http-client/json/http-client.xq.src/http_response_parser.cpp (+348/-0)
modules/http-client/json/http-client.xq.src/http_response_parser.h (+93/-0)
modules/http-client/json/http-client.xq.src/inform_data_read.cpp (+22/-0)
modules/http-client/json/http-client.xq.src/inform_data_read.h (+27/-0)
modules/http-client/json/http-client.xq.src/request_parser.cpp (+353/-0)
modules/http-client/json/http-client.xq.src/request_parser.h (+63/-0)
modules/http-client/xml/http-client-error.xq (+1/-1)
modules/http-client/xml/http-client.xq (+578/-55)
schemas/xslt-xquery-serialization.xsd (+1/-1)
src/api/CMakeLists.txt (+1/-0)
src/api/hexbinaryimpl.cpp (+83/-0)
src/api/item.cpp (+12/-0)
src/context/static_context.cpp (+3/-1)
test/rbkt/ExpQueryResults/zorba/http-client/json/delete/delete.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-binary/get-binary_binary.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-binary/get-binary_text.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-binary/get-binary_text_query.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-binary/get-binary_xml.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-binary/get-binary_xml_query.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-node/get-node_binary.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-node/get-node_text.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-node/get-node_text_query.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-node/get-node_xml.xml.res (+5/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-node/get-node_xml_query.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-text/get-text_binary.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-text/get-text_text.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-text/get-text_text_query.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-text/get-text_xml.xml.res (+5/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get-text/get-text_xml_query.xml.res (+5/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get/get_binary.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get/get_json.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get/get_text.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get/get_text_query.xml.res (+3/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get/get_xml.xml.res (+5/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/get/get_xml_query.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/head/head_content-type_binary.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/head/head_content-type_text.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/head/head_content-type_xml.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/head/head_status.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/options/options.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/post/post2_binary.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/post/post2_hexbinary.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/post/post2_json.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/post/post2_string.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/post/post3_binary.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/post/post3_json.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/post/post3_string.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/put/put2_binary.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/put/put2_hexbinary.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/put/put2_json.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/put/put2_string.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/put/put3_binary.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/put/put3_json.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/put/put3_string.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/send-request/http1-redirect.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/send-request/http1-useragent.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/send-request/http2-read-svg.xml.res (+11/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/send-request/http3-multipart.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/send-request/http3-post.xml.res (+12/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/send-request/http_error_hc002.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/send-request/http_error_hc004.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/send-request/http_error_hc005.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/send-request/send-request_get_binary.xml.res (+1/-0)
test/rbkt/ExpQueryResults/zorba/http-client/json/send-request/send-request_href.xml.res (+5/-0)
test/rbkt/ExpQueryResults/zorba/http-client/xml/get/get_json.xml.res (+4/-0)
test/rbkt/ExpQueryResults/zorba/http-client/xml/post/post3_binary_element.xml.res (+1/-1)
test/rbkt/ExpQueryResults/zorba/http-client/xml/put/put3_binary_element.xml.res (+1/-1)
test/rbkt/Queries/CMakeLists.txt (+0/-2)
test/rbkt/Queries/zorba/http-client/json/delete/delete.xq (+7/-0)
test/rbkt/Queries/zorba/http-client/json/delete/delete_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/delete/delete_error_http.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/get-binary/get-binary_binary.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get-binary/get-binary_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/get-binary/get-binary_error_http.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get-binary/get-binary_text.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get-binary/get-binary_text_query.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get-binary/get-binary_xml.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get-binary/get-binary_xml_query.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get-node/get-node_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/get-node/get-node_error_http.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/get-node/get-node_xml.xq (+3/-0)
test/rbkt/Queries/zorba/http-client/json/get-node/get-node_xml_query.xq (+4/-0)
test/rbkt/Queries/zorba/http-client/json/get-text/get-text_binary.xq (+4/-0)
test/rbkt/Queries/zorba/http-client/json/get-text/get-text_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/get-text/get-text_error_http.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get-text/get-text_text.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get-text/get-text_text_query.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get-text/get-text_xml.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get-text/get-text_xml_query.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get/get_binary.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get/get_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/get/get_error_http.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get/get_json.xq (+3/-0)
test/rbkt/Queries/zorba/http-client/json/get/get_text.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get/get_text_query.xq (+5/-0)
test/rbkt/Queries/zorba/http-client/json/get/get_xml.xq (+4/-0)
test/rbkt/Queries/zorba/http-client/json/get/get_xml_query.xq (+3/-0)
test/rbkt/Queries/zorba/http-client/json/head/head_content-type_binary.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/head/head_content-type_text.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/head/head_content-type_xml.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/head/head_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/head/head_error_http.xq (+9/-0)
test/rbkt/Queries/zorba/http-client/json/head/head_status.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/options/options.xq (+3/-0)
test/rbkt/Queries/zorba/http-client/json/options/options_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/options/options_error_http.xq (+3/-0)
test/rbkt/Queries/zorba/http-client/json/post/post2_binary.xq (+10/-0)
test/rbkt/Queries/zorba/http-client/json/post/post2_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/post/post2_error_http.xq (+8/-0)
test/rbkt/Queries/zorba/http-client/json/post/post2_hexbinary.xq (+11/-0)
test/rbkt/Queries/zorba/http-client/json/post/post2_json.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/post/post2_string.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/post/post3_binary.xq (+9/-0)
test/rbkt/Queries/zorba/http-client/json/post/post3_encoding_error.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/post/post3_encoding_error.xq (+7/-0)
test/rbkt/Queries/zorba/http-client/json/post/post3_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/post/post3_error_http.xq (+9/-0)
test/rbkt/Queries/zorba/http-client/json/post/post3_json.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/post/post3_string.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/put/put2_binary.xq (+11/-0)
test/rbkt/Queries/zorba/http-client/json/put/put2_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/put/put2_error_http.xq (+8/-0)
test/rbkt/Queries/zorba/http-client/json/put/put2_hexbinary.xq (+10/-0)
test/rbkt/Queries/zorba/http-client/json/put/put2_json.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/put/put2_string.xq (+8/-0)
test/rbkt/Queries/zorba/http-client/json/put/put3_binary.xq (+9/-0)
test/rbkt/Queries/zorba/http-client/json/put/put3_error_http.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/put/put3_error_http.xq (+9/-0)
test/rbkt/Queries/zorba/http-client/json/put/put3_json.xq (+6/-0)
test/rbkt/Queries/zorba/http-client/json/put/put3_string.xq (+7/-0)
test/rbkt/Queries/zorba/http-client/json/send-request/http1-redirect.xq (+32/-0)
test/rbkt/Queries/zorba/http-client/json/send-request/http1-useragent.xq (+18/-0)
test/rbkt/Queries/zorba/http-client/json/send-request/http2-read-svg.xq (+20/-0)
test/rbkt/Queries/zorba/http-client/json/send-request/http3-multipart.xq (+52/-0)
test/rbkt/Queries/zorba/http-client/json/send-request/http3-post.xq (+19/-0)
test/rbkt/Queries/zorba/http-client/json/send-request/http4-post-redirect.spec (+1/-0)
test/rbkt/Queries/zorba/http-client/json/send-request/http4-post-redirect.xq (+13/-0)
test/rbkt/Queries/zorba/http-client/json/send-request/http_error_hc005.xq (+65/-0)
test/rbkt/Queries/zorba/http-client/json/send-request/send-request_get_binary.xq (+22/-0)
test/rbkt/Queries/zorba/http-client/json/send-request/send-request_href.xq (+10/-0)
test/rbkt/Queries/zorba/http-client/xml/get/get_json.xq (+3/-0)
test/rbkt/Queries/zorba/http-client/xml/send-request/http3-post.xq (+0/-1)
To merge this branch: bzr merge lp:~zorba-coders/zorba/json-http-module
Reviewer Review Type Date Requested Status
Chris Hillery Approve on 2013-07-24
Cezar Andrei 2013-06-15 Approve on 2013-06-24
Review via email: mp+169579@code.launchpad.net

Commit Message

Added JSON HTTP client module.
Fixed initialization, error reporting and encoding bugs in the XML HTTP client.
Reimplemented XML HTTP client on top of the JSON HTTP client module.

Description of the Change

JSON HTTP Client Module

To post a comment you must log in.
Cezar Andrei (cezar-andrei) wrote :

Code looks good. I need a few more tests to make sure everything is fine.

Cezar Andrei (cezar-andrei) wrote :

In the Doc examples use WWW.zorba.io... but the module is registered without WWW:

xqDoc:
import module namespace http="http://www.zorba.io/modules/http-client";
http:get("http://www.example.com")

review: Needs Fixing
Cezar Andrei (cezar-andrei) wrote :

"timeout" option has a bug. Uncomment "timeout" in the following script and get this error:

$ ./zorba -i -f -q q.jq
error [zerr:ZSTR0040]: type error: Item::getIntValue() not defined for type "xs:integer"

jsoniq version "1.0";
import module namespace http="http://zorba.io/modules/http-client";

http:send-request(
{
  "method": "POST",
  "href": "http://requestb.in/13727yx1",
  "authentication":
  {
    "username" : "user",
    "password" : "pass",
    "auth-method" : "Basic"
  },
  "options":
  {
    "status-only": true,
    "override-media-type": "text/plain",
    "follow-redirect": true,
    (: "timeout": "30", :)
    "user-agent": "Mozilla/5.0"
  },
  "headers":
  {
    "name": "value"
  },
  "body":
  {
    "media-type": "text/plain",
    "content": "..."
  }
})

Cezar Andrei (cezar-andrei) wrote :

Also, add a note on the module documentation section about using the header jsoniq version "1.0"; at the top and put a link to a page that describes this header.

review: Needs Fixing
Chris Hillery (ceejatec) wrote :

> Also, add a note on the module documentation section about using the header
> jsoniq version "1.0"; at the top and put a link to a page that describes this
> header.

Cezar, it is not necessary for users to have a jsoniq version header in their queries to use this module. They can use ("field") object accessors instead of .field .

Cezar Andrei (cezar-andrei) wrote :

> Cezar, it is not necessary for users to have a jsoniq version header in their
> queries to use this module. They can use ("field") object accessors instead of
> .field .

My point was to mention these options somewhere in the doc and link to a page which better describes this. IMHO it's confusing if you also count in the file extension .jq.

> "timeout" option has a bug. Uncomment "timeout" in the following script and
> get this error:
>
> $ ./zorba -i -f -q q.jq
> error [zerr:ZSTR0040]: type error: Item::getIntValue() not defined for type
> "xs:integer"
>
>
> jsoniq version "1.0";
> import module namespace http="http://zorba.io/modules/http-client";
>
> http:send-request(
> {
> "method": "POST",
> "href": "http://requestb.in/13727yx1",
> "authentication":
> {
> "username" : "user",
> "password" : "pass",
> "auth-method" : "Basic"
> },
> "options":
> {
> "status-only": true,
> "override-media-type": "text/plain",
> "follow-redirect": true,
> (: "timeout": "30", :)
> "user-agent": "Mozilla/5.0"
> },
> "headers":
> {
> "name": "value"
> },
> "body":
> {
> "media-type": "text/plain",
> "content": "..."
> }
> })

Federico, the problem occurs because getIntValue only works for xs:int items and not for xs:integer. However, because there is no representation of an arbitrary precision integer in the API, you have to do a trick as follows:

  Item lTmp = aOptions.getObjectValue("timeout");
  if (!lTmp.isNull())
  {
    if (lTmp.getTypeCode() != store::XS_INTEGER)
    {
      // raiseTypeError(lTmp.getType(), "timeout", "integer");
    }
    else
    {
      aValue = atoi(lTmp.getStringValue().c_str());
    }
  }
  else
  {
    aValue = 0;
  }

Federico Cavalieri (fcavalieri) wrote :

> In the Doc examples use WWW.zorba.io... but the module is registered without
> WWW:
>
> xqDoc:
> import module namespace http="http://www.zorba.io/modules/http-client";
> http:get("http://www.example.com")

Fixed

> "timeout" option has a bug. Uncomment "timeout" in the following script and get this error:
> $ ./zorba -i -f -q q.jq
> error [zerr:ZSTR0040]: type error: Item::getIntValue() not defined for type "xs:integer"
Fixed and added test

Federico Cavalieri (fcavalieri) wrote :

> > Cezar, it is not necessary for users to have a jsoniq version header in
> their
> > queries to use this module. They can use ("field") object accessors instead
> of
> > .field .
>
> My point was to mention these options somewhere in the doc and link to a page
> which better describes this. IMHO it's confusing if you also count in the file
> extension .jq.

The file extension is .xq, should I make it .jq?
Thanks

Federico Cavalieri (fcavalieri) wrote :

> > Cezar, it is not necessary for users to have a jsoniq version header in
> their
> > queries to use this module. They can use ("field") object accessors instead
> of
> > .field .
>
> My point was to mention these options somewhere in the doc and link to a page
> which better describes this. IMHO it's confusing if you also count in the file
> extension .jq.

I added a small note which says that the module is written in jsoniq and that can be imported
both by xquery and jsoniq modules.
However, I don't know which webpage should I link to explain the version declaration: jsoniq.org does not mention this header, which I only found discussed in http://www.zorba.io/blog/. A link to this page would soon become outdated and I don't know how to get the specific post url. Any suggestions?
Thanks

>>> Cezar, it is not necessary for users to have a jsoniq version header in
>> their
>>> queries to use this module. They can use ("field") object accessors instead
>> of
>>> .field .
>>
>> My point was to mention these options somewhere in the doc and link to a page
>> which better describes this. IMHO it's confusing if you also count in the file
>> extension .jq.
>
> I added a small note which says that the module is written in jsoniq and that can be imported
> both by xquery and jsoniq modules.
> However, I don't know which webpage should I link to explain the version declaration: jsoniq.org does not mention this header, which I only found discussed in http://www.zorba.io/blog/. A link to this page would soon become outdated and I don't know how to get the specific post url. Any suggestions?
> Thanks
I think that's fine. Leave it like this. Zorba still has to catch up to make .jq modules
possible. Once this is done, we need some general documentation for such cases.

> --
> https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579
> You are subscribed to branch lp:zorba.

Chris Hillery (ceejatec) wrote :

IMHO, it's not a good idea to have any notes in module docs about how to use JSONiq. Virtually ask of our modules will have the same concerns, so we'd need to duplicate it dozens of times. This isn't the appropriate location for that information. I would take out that doc.

Federico Cavalieri (fcavalieri) wrote :

I merged the trunk into the branch and added the ability to use hexbinary as a body type.
Note that this required a further API extension beside in addtion to the hexbinary stream which has been merged into the trunk a few hours ago.

Removed the jsoniq note from docs

Cezar Andrei (cezar-andrei) wrote :

Checked the integer issue and is fixed also done more testing. Looks good.

review: Approve
Chris Hillery (ceejatec) wrote :

1. OMG code duplication: the entire contents of http-client.xq.src is copied (and modified?) from the original http-client module. That's nearly 3000 lines of some of the ugliest and most error-filled code we've got. No way do we want to maintain two copies of it. Also, they both call curl_global_init() and curl_global_cleanup(), which means that they will stomp on each other if anyone attempts to use both. This code must be consolidated somehow, perhaps into a common library that both modules use. Or, we need to simply eliminate the original http-client library. Perhaps we could replace the old http-client module with a pure XQuery wrapper module that replicates the old API, much like V2 of the EXPath http-client module does?

2. Need to consolidate the CMake code which searches for curl, etc. It was copied from modules/com/zorba-xquery/www/modules/CMakeLists.txt, and it still exists in that location. That means the search for CURL is done twice, and the cached variable ZORBA_HAVE_CURL is defined twice, and the Windows .pem files are copied twice... I would suggest that it should remain where it is in modules/CMakeList.txt, and be deleted from the other location, and testing done to ensure it still works right. (This issue would also be resolved by eliminating the original http-client module or replacing it with a wrapper module.)

3. The module error codes need to be changed to match the coding guidelines: http://my.zorba.io/dokuwiki/doku.php?id=coding-guidelines#error_codes

review: Needs Fixing
Federico Cavalieri (fcavalieri) wrote :

Thank you for your feedback.

> 3. The module error codes need to be changed to match the coding guidelines:
> http://my.zorba.io/dokuwiki/doku.php?id=coding-guidelines#error_codes

I updated the error codes according to the guidelines

Federico Cavalieri (fcavalieri) wrote :

> 1. OMG code duplication: the entire contents of http-client.xq.src is copied
> (and modified?) from the original http-client module. That's nearly 3000 lines
> of some of the ugliest and most error-filled code we've got. No way do we want
> to maintain two copies of it. Also, they both call curl_global_init() and
> curl_global_cleanup(), which means that they will stomp on each other if
> anyone attempts to use both. This code must be consolidated somehow, perhaps
> into a common library that both modules use. Or, we need to simply eliminate
> the original http-client library. Perhaps we could replace the old http-client
> module with a pure XQuery wrapper module that replicates the old API, much
> like V2 of the EXPath http-client module does?
>
> 2. Need to consolidate the CMake code which searches for curl, etc. It was
> copied from modules/com/zorba-xquery/www/modules/CMakeLists.txt, and it still
> exists in that location. That means the search for CURL is done twice, and the
> cached variable ZORBA_HAVE_CURL is defined twice, and the Windows .pem files
> are copied twice... I would suggest that it should remain where it is in
> modules/CMakeList.txt, and be deleted from the other location, and testing
> done to ensure it still works right. (This issue would also be resolved by
> eliminating the original http-client module or replacing it with a wrapper
> module.)

Yes, part of the code of the json-http-client duplicates that of the original
http-client-module. It is not 100% the same because, as you said, because
the original contains several bugs. The bugs I found (which include, headers mangling,
broken/absent charset encoding/decoding, broken/absent streamable string and binary
support, error reporting, and so on) are fixed in the JSON HTTP module code.

I believe that removing the old http-client module would solve many problems,
but given the widespread use of this module I am not sure if this is feasible.
I remember that when I started working on this module there was a discussion on
this option and that keeping the old module (and duplicating the code) was the
final decision.
However, my knowledge in this respect is limited, so I am not sure.

The next best thing would be to replace the old module with a wrapper.
The only downside of this is that some of the old module bugs are really common,
e.g.: all requests which do not contain a manually specified "charset=UTF-8"
specification in the media-type are sent with a wrong encoding.

Therefore, I will begin to work on the wrapper.

Federico Cavalieri (fcavalieri) wrote :

The old http-module when you send an http-request, specifying a non textual mime-type, the current http-client invokes the serializer specifiying the (unaccessible from XQuery code) "binary" method.

If the body is an xml node it gets converted in a very strange way:
<hello>there</hello> becomes "hello there" then it is encoded as base64 and sent encoded.
There is a test which specifically verifies this case.

Trying to send a JSON object results in an error.
A base64 value is sent encoded as is.
Anything else is first converted into a string and then encoded in base64.

I personally believe that this does not make sense at all and the JSON http client behaves differently.

Is this really the intended behaviour (there is a test which verifies it)?
Is there some code depending on it?
What is the rationale of the conversion from <hello>there</hello> to "hello there" (it cannot even be reproduced without a UDF)?
Should I reproduce this behaviour?

Federico Cavalieri (fcavalieri) wrote :

>
> The old http-module when you send an http-request, specifying a non textual
> mime-type, the current http-client invokes the serializer specifiying the
> (unaccessible from XQuery code) "binary" method.
>
I meant
The old http-module when you send an http-request, specifying a non textual mime-type, invokes the serializer specifiying the (unaccessible from XQuery code) "binary" method.

Federico Cavalieri (fcavalieri) wrote :

Chris, thanks for the comments.

I think I resolved all reported issues with the module.
The old http module is xquery only now.
I also did a cleaning pass over the cpp and removed two small initialization bugs.

Chris Hillery (ceejatec) wrote :

Looks good, thanks!

review: Approve
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

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

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue result for https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

Stage "BuildZorbaUbuntu" failed.

Check compiler output at http://jenkins.lambda.nu/job/BuildZorbaUbuntu/127/parsed_console to view the results.

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

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

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

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

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

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

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

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

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue result for https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

Stage "TestZorbaUbuntu" failed.
158 tests failed (8414 total tests run).

Check test results at http://jenkins.lambda.nu/job/TestZorbaUbuntu/114/testReport/ to view the results.

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

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

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

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

11530. By Federico Cavalieri on 2013-07-25

Fixed recursive loading of module

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

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

Zorba Build Bot (zorba-buildbot) wrote :

Voting criteria failed for the following merge proposals:

https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579 :
Votes: {'Approve': 2, 'Needs commit message': 1}

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue result for https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

Stage "CommitZorba" failed.

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

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/json-http-module/+merge/169579

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

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue succeeded - proposal merged!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/zorba/item.h'
2--- include/zorba/item.h 2013-06-29 08:38:53 +0000
3+++ include/zorba/item.h 2013-07-25 09:33:27 +0000
4@@ -484,6 +484,21 @@
5 size_t
6 mem_size() const;
7
8+ /**
9+ * Returns the value and size of the given hexBinary item
10+ *
11+ * The value is a string which is hexBinary encoded if isEncoded()
12+ * returns true. Otherwise, it is the original unencoded binary
13+ * data.
14+ *
15+ * If the given item is streamable (i.e. isStreamable() returns true),
16+ * the stream returned by getStream() should to be used to retrieve
17+ * the value. Otherwise, the contents of the stream will be materialized
18+ * in main memory.
19+ */
20+ const char*
21+ getHexBinaryValue(size_t& s) const;
22+
23 private:
24 friend class Unmarshaller;
25
26
27=== added file 'include/zorba/util/hexbinary_util.h'
28--- include/zorba/util/hexbinary_util.h 1970-01-01 00:00:00 +0000
29+++ include/zorba/util/hexbinary_util.h 2013-07-25 09:33:27 +0000
30@@ -0,0 +1,51 @@
31+/*
32+ * Copyright 2006-2009 The FLWOR Foundation.
33+ *
34+ * Licensed under the Apache License, Version 2.0 (the "License");
35+ * you may not use this file except in compliance with the License.
36+ * You may obtain a copy of the License at
37+ *
38+ * http://www.apache.org/licenses/LICENSE-2.0
39+ *
40+ * Unless required by applicable law or agreed to in writing, software
41+ * distributed under the License is distributed on an "AS IS" BASIS,
42+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
43+ * See the License for the specific language governing permissions and
44+ * limitations under the License.
45+ */
46+
47+#ifndef ZORBA_HEXBINARY_API_H
48+#define ZORBA_HEXBINARY_API_H
49+
50+// standard
51+#include <iostream>
52+
53+// zorba
54+#include <zorba/config.h>
55+#include <zorba/zorba_string.h>
56+
57+namespace zorba {
58+namespace hexbinary {
59+
60+///////////////////////////////////////////////////////////////////////////////
61+
62+ZORBA_DLL_PUBLIC
63+String encode( String const &aString );
64+
65+ZORBA_DLL_PUBLIC
66+String encode( std::istream &aStream );
67+
68+ZORBA_DLL_PUBLIC
69+String decode( String const &aString );
70+
71+ZORBA_DLL_PUBLIC
72+String decode( std::istream &aStream );
73+
74+///////////////////////////////////////////////////////////////////////////////
75+
76+} // namespace hexbinary
77+} // namespace zorba
78+
79+#endif /* ZORBA_HEXBINARY_API_H */
80+/* vim:set et sw=2 ts=2: */
81+
82
83=== modified file 'modules/CMakeLists.txt'
84--- modules/CMakeLists.txt 2013-07-17 15:53:51 +0000
85+++ modules/CMakeLists.txt 2013-07-25 09:33:27 +0000
86@@ -19,6 +19,7 @@
87 ADD_SUBDIRECTORY(xqxq)
88 ADD_SUBDIRECTORY(w3c)
89 ADD_SUBDIRECTORY(full-text)
90+ADD_SUBDIRECTORY(http-client)
91 ADD_SUBDIRECTORY(json)
92 ADD_SUBDIRECTORY(nodes)
93
94
95=== modified file 'modules/com/zorba-xquery/www/modules/CMakeLists.txt'
96--- modules/com/zorba-xquery/www/modules/CMakeLists.txt 2013-07-17 15:48:38 +0000
97+++ modules/com/zorba-xquery/www/modules/CMakeLists.txt 2013-07-25 09:33:27 +0000
98@@ -12,45 +12,6 @@
99 # See the License for the specific language governing permissions and
100 # limitations under the License.
101
102-
103-#
104-# cURL
105-#
106-SET (CURL_FOUND)
107-IF(ZORBA_SUPPRESS_CURL)
108- MESSAGE(STATUS "ZORBA_SUPPRESS_CURL is true - not searching for cURL library")
109-ELSE(ZORBA_SUPPRESS_CURL)
110- MESSAGE(STATUS "Looking for cURL")
111- FIND_PACKAGE(CURL)
112-
113- IF(CURL_FOUND)
114- MESSAGE(STATUS "Found cURL library -- " ${CURL_LIBRARIES})
115- INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
116- DECLARE_ZORBA_MODULE(FILE http-client-error.xq
117- URI "http://expath.org/ns/error")
118- DECLARE_ZORBA_SCHEMA(FILE http-client.xsd
119- URI "http://expath.org/ns/http-client")
120- DECLARE_ZORBA_MODULE(FILE http-client.xq VERSION 2.0
121- URI "http://www.zorba-xquery.com/modules/http-client"
122- LINK_LIBRARIES ${CURL_LIBRARIES})
123-
124- IF (WIN32) # Copy certificates for windows only
125- IF (MSVC_IDE)
126- SET(CACERT_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../../../../../bin/${CMAKE_BUILD_TYPE}/cacert.pem")
127- ELSE (MSVC_IDE)
128- SET(CACERT_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../../../../../bin/cacert.pem")
129- ENDIF (MSVC_IDE)
130- CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cacert.pem" ${CACERT_DESTINATION} COPYONLY)
131- INSTALL(FILES ${CACERT_DESTINATION} DESTINATION bin)
132- ENDIF (WIN32)
133-
134- ELSE(CURL_FOUND)
135- MESSAGE(STATUS "The cURL library was not found - http-client will not be built")
136- ENDIF(CURL_FOUND)
137-ENDIF(ZORBA_SUPPRESS_CURL)
138-SET(ZORBA_HAVE_CURL ${CURL_FOUND} CACHE BOOL "Whether Zorba found cURL" FORCE)
139-MARK_AS_ADVANCED(ZORBA_HAVE_CURL)
140-
141 DECLARE_ZORBA_SCHEMA(FILE xqdoc.xsd URI "http://www.xqdoc.org/1.0")
142 DECLARE_ZORBA_MODULE(FILE datetime.xq VERSION 2.0
143 URI "http://www.zorba-xquery.com/modules/datetime")
144
145=== removed directory 'modules/com/zorba-xquery/www/modules/http-client.xq.src'
146=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_overwrite.h'
147--- modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_overwrite.h 2013-02-07 17:24:36 +0000
148+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_overwrite.h 1970-01-01 00:00:00 +0000
149@@ -1,23 +0,0 @@
150-/*
151- * Copyright 2006-2008 The FLWOR Foundation.
152- *
153- * Licensed under the Apache License, Version 2.0 (the "License");
154- * you may not use this file except in compliance with the License.
155- * You may obtain a copy of the License at
156- *
157- * http://www.apache.org/licenses/LICENSE-2.0
158- *
159- * Unless required by applicable law or agreed to in writing, software
160- * distributed under the License is distributed on an "AS IS" BASIS,
161- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
162- * See the License for the specific language governing permissions and
163- * limitations under the License.
164- */
165-
166-#ifndef CURL_OVERWRITE_H
167-#define CURL_OVERWRITE_H
168-
169-#include "curl_wrappers.h"
170-#include "curl_redefines.h"
171-
172-#endif // CURL_OVERWRITE_H
173
174=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_redefines.h'
175--- modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_redefines.h 2013-02-07 17:24:36 +0000
176+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_redefines.h 1970-01-01 00:00:00 +0000
177@@ -1,30 +0,0 @@
178-/*
179- * Copyright 2006-2008 The FLWOR Foundation.
180- *
181- * Licensed under the Apache License, Version 2.0 (the "License");
182- * you may not use this file except in compliance with the License.
183- * You may obtain a copy of the License at
184- *
185- * http://www.apache.org/licenses/LICENSE-2.0
186- *
187- * Unless required by applicable law or agreed to in writing, software
188- * distributed under the License is distributed on an "AS IS" BASIS,
189- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190- * See the License for the specific language governing permissions and
191- * limitations under the License.
192- */
193-
194-#ifndef CURL_REDEFINES_H
195-#define CURL_REDEFINES_H
196-
197-#define curl_easy_init() curl_easy_init_wrapped(__FILE__, __LINE__)
198-#define curl_multi_init() curl_multi_init_wrapped(__FILE__, __LINE__)
199-#define curl_easy_setopt(x, y, z) curl_easy_setopt_wrapped(__FILE__, __LINE__, x, y, z)
200-//#define curl_multi_perform(x,y) curl_multi_perform_wrapped(__FILE__, __LINE__, x, y)
201-//#define curl_multi_info_read(x,y) curl_multi_info_read_wrapped(__FILE__, __LINE__, x, y)
202-#define curl_slist_free_all(x) curl_slist_free_all_wrapped(__FILE__, __LINE__, x)
203-#define curl_formfree(x) curl_formfree_wrapped(__FILE__, __LINE__, x)
204-#define curl_slist_append(x,y) curl_slist_append_wrapped(__FILE__, __LINE__, x, y)
205-#define curl_multi_add_handle(x,y) curl_multi_add_handle_wrapped(__FILE__, __LINE__, x, y)
206-
207-#endif // CURL_REDEFINES_H
208
209=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_stream_buffer.cpp'
210--- modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_stream_buffer.cpp 2013-02-07 17:24:36 +0000
211+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_stream_buffer.cpp 1970-01-01 00:00:00 +0000
212@@ -1,379 +0,0 @@
213-/*
214- * Copyright 2006-2008 The FLWOR Foundation.
215- *
216- * Licensed under the Apache License, Version 2.0 (the "License");
217- * you may not use this file except in compliance with the License.
218- * You may obtain a copy of the License at
219- *
220- * http://www.apache.org/licenses/LICENSE-2.0
221- *
222- * Unless required by applicable law or agreed to in writing, software
223- * distributed under the License is distributed on an "AS IS" BASIS,
224- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
225- * See the License for the specific language governing permissions and
226- * limitations under the License.
227- */
228-
229-#include <zorba/config.h>
230-
231-#include <cstdlib>
232-#include <cstring> /* for memcpy(3) */
233-#include <iostream>
234-#include <cassert>
235-#ifndef WIN32
236-#include <cerrno>
237-#include <sys/time.h>
238-#endif /* WIN32 */
239-
240-#include <curl/multi.h>
241-
242-#include "curl_stream_buffer.h"
243-#include "inform_data_read.h"
244-
245-using namespace std;
246-
247-namespace zorba {
248-namespace curl {
249-
250-///////////////////////////////////////////////////////////////////////////////
251-
252-#define ZORBA_CURL_ASSERT(expr) \
253- do { \
254- if ( CURLcode const code##__LINE__ = (expr) ) \
255- throw exception( #expr, "", code##__LINE__ ); \
256- } while (0)
257-
258-#define ZORBA_CURLM_ASSERT(expr) \
259- do { \
260- if ( CURLMcode const code##__LINE__ = (expr) ) \
261- if ( code##__LINE__ != CURLM_CALL_MULTI_PERFORM ) \
262- throw exception( #expr, "", code##__LINE__ ); \
263- } while (0)
264-
265-exception::exception( char const *function, char const *uri, char const *msg ) :
266- std::exception(), msg_( msg )
267-{
268-}
269-
270-exception::exception( char const *function, char const *uri, CURLcode code ) :
271- std::exception(),
272- msg_( curl_easy_strerror( code ) )
273-{
274-}
275-
276-exception::exception( char const *function, char const *uri, CURLMcode code ) :
277- std::exception(),
278- msg_( curl_multi_strerror( code ) )
279-{
280-}
281-
282-exception::~exception() throw() {
283- // out-of-line since it's virtual
284-}
285-
286-const char* exception::what() const throw() {
287- return msg_.c_str();
288-}
289-
290-///////////////////////////////////////////////////////////////////////////////
291-
292-CURL* create( char const *uri, write_fn_t fn, void *data ) {
293- //
294- // Having cURL initialization wrapped by a class and using a singleton static
295- // instance guarantees that cURL is initialized exactly once before use and
296- // and also is cleaned-up at program termination (when destructors for static
297- // objects are called).
298- //
299- struct curl_initializer {
300- curl_initializer() {
301- ZORBA_CURL_ASSERT( curl_global_init( CURL_GLOBAL_ALL ) );
302- }
303- ~curl_initializer() {
304- curl_global_cleanup();
305- }
306- };
307- static curl_initializer initializer;
308-
309- CURL *const curl = curl_easy_init();
310- if ( !curl )
311- throw exception( "curl_easy_init()", uri, "" );
312-
313- try {
314- ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_URL, uri ) );
315- ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEDATA, data ) );
316- ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, fn ) );
317-
318- // Tells cURL to follow redirects. CURLOPT_MAXREDIRS is by default set to -1
319- // thus cURL will do an infinite number of redirects.
320- ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1 ) );
321-
322-#ifndef ZORBA_VERIFY_PEER_SSL_CERTIFICATE
323- ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 0 ) );
324- //
325- // CURLOPT_SSL_VERIFYHOST is left default, value 2, meaning verify that the
326- // Common Name or Subject Alternate Name field in the certificate matches
327- // the name of the server.
328- //
329- // Tested with https://www.npr.org/rss/rss.php?id=1001
330- // About using SSL certs in curl: http://curl.haxx.se/docs/sslcerts.html
331-#else
332-# ifdef WIN32
333- // set the root CA certificates file path
334- if ( GENV.g_curl_root_CA_certificates_path[0] )
335- ZORBA_CURL_ASSERT(
336- curl_easy_setopt(
337- curl, CURLOPT_CAINFO, GENV.g_curl_root_CA_certificates_path
338- )
339- );
340-# endif /* WIN32 */
341-#endif /* ZORBA_VERIFY_PEER_SSL_CERTIFICATE */
342-
343- //
344- // Some servers don't like requests that are made without a user-agent
345- // field, so we provide one.
346- //
347- ZORBA_CURL_ASSERT(
348- curl_easy_setopt( curl, CURLOPT_USERAGENT, "libcurl-agent/1.0" )
349- );
350-
351- return curl;
352- }
353- catch ( ... ) {
354- destroy( curl );
355- throw;
356- }
357-}
358-
359-void destroy( CURL *curl ) {
360- if ( curl ) {
361- curl_easy_reset( curl );
362- curl_easy_cleanup( curl );
363- }
364-}
365-
366-///////////////////////////////////////////////////////////////////////////////
367-
368-streambuf::streambuf() {
369- init();
370-}
371-
372-streambuf::streambuf( char const *uri ) {
373- init();
374- open( uri );
375-}
376-
377-streambuf::streambuf( CURL *curl ) {
378- init();
379- curl_ = curl;
380- ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEDATA, this ) );
381- ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, curl_write_callback ) );
382- init_curlm();
383-}
384-
385-streambuf::~streambuf() {
386- free( buf_ );
387- close();
388-#ifdef WIN32
389- closesocket( dummy_socket_ );
390-#endif
391- // If we have been assigned memory ownership of theInformer, delete it now.
392- if ( theOwnInformer )
393- delete theInformer;
394-}
395-
396-void streambuf::close() {
397- if ( curl_ ) {
398- if ( curlm_ ) {
399- curl_multi_remove_handle( curlm_, curl_ );
400- curl_multi_cleanup( curlm_ );
401- curlm_ = 0;
402- }
403- destroy( curl_ );
404- curl_ = 0;
405- }
406-}
407-
408-void streambuf::curl_read() {
409- buf_len_ = 0;
410- while ( curl_running_ && !buf_len_ ) {
411- fd_set fd_read, fd_write, fd_except;
412- FD_ZERO( &fd_read );
413- FD_ZERO( &fd_write );
414- FD_ZERO( &fd_except );
415- int max_fd = -1;
416-#ifdef WIN32
417- //
418- // Windows does not like a call to select where all arguments are 0, so we
419- // just add a dummy socket to make the call to select happy.
420- //
421- FD_SET( dummy_socket_, &fd_read );
422-#endif /* WIN32 */
423- ZORBA_CURLM_ASSERT(
424- curl_multi_fdset( curlm_, &fd_read, &fd_write, &fd_except, &max_fd )
425- );
426-
427- //
428- // Note that the fopen.c sample code is unnecessary at best or wrong at
429- // worst; see: http://curl.haxx.se/mail/lib-2011-05/0011.html
430- //
431- timeval timeout;
432- long curl_timeout_ms;
433- ZORBA_CURLM_ASSERT( curl_multi_timeout( curlm_, &curl_timeout_ms ) );
434- if ( curl_timeout_ms > 0 ) {
435- timeout.tv_sec = curl_timeout_ms / 1000;
436- timeout.tv_usec = curl_timeout_ms % 1000 * 1000;
437- } else {
438- //
439- // From curl_multi_timeout(3):
440- //
441- // Note: if libcurl returns a -1 timeout here, it just means that
442- // libcurl currently has no stored timeout value. You must not wait
443- // too long (more than a few seconds perhaps) before you call
444- // curl_multi_perform() again.
445- //
446- // So we just pick some not-too-long default.
447- //
448- timeout.tv_sec = 1;
449- timeout.tv_usec = 0;
450- }
451-
452- switch ( select( max_fd + 1, &fd_read, &fd_write, &fd_except, &timeout ) ) {
453- case -1: // select error
454-#ifdef WIN32
455- char err_buf[8];
456- sprintf( err_buf, "%d", WSAGetLastError() );
457- throw exception( "select()", "", err_buf );
458-#else
459- throw exception( "select()", "", strerror( errno ) );
460-#endif
461- case 0: // timeout
462- // no break;
463- default:
464- CURLMcode code;
465- do {
466- code = curl_multi_perform( curlm_, &curl_running_ );
467- } while ( code == CURLM_CALL_MULTI_PERFORM );
468- ZORBA_CURLM_ASSERT( code );
469- }
470- }
471- if ( theInformer )
472- theInformer->afterRead();
473-}
474-
475-size_t streambuf::curl_write_callback( void *ptr, size_t size, size_t nmemb,
476- void *data ) {
477- size *= nmemb;
478- streambuf *const that = static_cast<streambuf*>( data );
479-
480- if ( that->theInformer )
481- that->theInformer->beforeRead();
482-
483- size_t const buf_free = that->buf_capacity_ - that->buf_len_;
484- if ( size > buf_free ) {
485- streamoff new_capacity = that->buf_capacity_ + size - buf_free;
486- if ( void *const new_buf =
487- realloc( that->buf_, static_cast<size_t>( new_capacity ) ) ) {
488- that->buf_ = static_cast<char*>( new_buf );
489- that->buf_capacity_ = new_capacity;
490- } else
491- throw exception( "realloc()", "" );
492- }
493- ::memcpy( that->buf_ + that->buf_len_, ptr, size );
494- that->buf_len_ += size;
495- return size;
496-}
497-
498-void streambuf::init() {
499- buf_ = 0;
500- buf_capacity_ = 0;
501- buf_len_ = 0;
502- curl_ = 0;
503- curlm_ = 0;
504- curl_running_ = 0;
505- theInformer = 0;
506- theOwnInformer = false;
507-#ifdef WIN32
508- dummy_socket_ = socket( AF_INET, SOCK_DGRAM, 0 );
509- if ( dummy_socket_ == CURL_SOCKET_BAD || dummy_socket_ == INVALID_SOCKET )
510- throw exception( "socket()", "" );
511-#endif /* WIN32 */
512-}
513-
514-void streambuf::init_curlm() {
515- //
516- // Lie about cURL running initially so the while-loop in curl_read() will run
517- // at least once.
518- //
519- curl_running_ = 1;
520-
521- //
522- // Set the "get" pointer to the end (gptr() == egptr()) so a call to
523- // underflow() and initial data read will be triggered.
524- //
525- buf_len_ = buf_capacity_;
526- setg( buf_, buf_ + buf_len_, buf_ + buf_capacity_ );
527-
528- //
529- // Clean-up has to be done here with try/catch (as opposed to relying on the
530- // destructor) because open() can be called from the constructor. If an
531- // exception is thrown, the constructor will not have completed, hence the
532- // object will not have been fully constructed; therefore the destructor will
533- // not be called.
534- //
535- try {
536- if ( !(curlm_ = curl_multi_init()) )
537- throw exception( "curl_multi_init()", "" );
538- try {
539- ZORBA_CURLM_ASSERT( curl_multi_add_handle( curlm_, curl_ ) );
540- }
541- catch ( ... ) {
542- curl_multi_cleanup( curlm_ );
543- curlm_ = 0;
544- throw;
545- }
546- }
547- catch ( ... ) {
548- destroy( curl_ );
549- curl_ = 0;
550- throw;
551- }
552-}
553-
554-int streambuf::multi_perform() {
555- underflow();
556- CURLMsg *msg;
557- int msgInQueue;
558- int error = 0;
559- while ( (msg = curl_multi_info_read( curlm_, &msgInQueue )) ) {
560- if ( msg->msg == CURLMSG_DONE )
561- error = msg->data.result;
562- }
563- return error;
564-}
565-
566-void streambuf::open( char const *uri ) {
567- curl_ = create( uri, curl_write_callback, this );
568-
569- init_curlm();
570-}
571-
572-streamsize streambuf::showmanyc() {
573- return egptr() - gptr();
574-}
575-
576-streambuf::int_type streambuf::underflow() {
577- while ( true ) {
578- if ( gptr() < egptr() )
579- return traits_type::to_int_type( *gptr() );
580- curl_read();
581- if ( !buf_len_ )
582- return traits_type::eof();
583- setg( buf_, buf_, buf_ + buf_len_ );
584- }
585-}
586-
587-///////////////////////////////////////////////////////////////////////////////
588-
589-} // namespace curl
590-} // namespace zorba
591-/* vim:set et sw=2 ts=2: */
592
593=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_stream_buffer.h'
594--- modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_stream_buffer.h 2013-02-07 17:24:36 +0000
595+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_stream_buffer.h 1970-01-01 00:00:00 +0000
596@@ -1,193 +0,0 @@
597-/*
598- * Copyright 2006-2008 The FLWOR Foundation.
599- *
600- * Licensed under the Apache License, Version 2.0 (the "License");
601- * you may not use this file except in compliance with the License.
602- * You may obtain a copy of the License at
603- *
604- * http://www.apache.org/licenses/LICENSE-2.0
605- *
606- * Unless required by applicable law or agreed to in writing, software
607- * distributed under the License is distributed on an "AS IS" BASIS,
608- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
609- * See the License for the specific language governing permissions and
610- * limitations under the License.
611- */
612-#pragma once
613-#ifndef ZORBA_CURL_UTIL_H
614-#define ZORBA_CURL_UTIL_H
615-
616-#include <zorba/config.h>
617-
618-#include <exception>
619-#include <istream>
620-#include <streambuf>
621-#include <string>
622-#include <curl/curl.h>
623-
624-namespace zorba {
625-
626-namespace http_client {
627- class InformDataRead;
628-}
629-
630-namespace curl {
631-
632-///////////////////////////////////////////////////////////////////////////////
633-
634-class exception : public std::exception {
635-public:
636- exception( char const *function, char const *uri, char const *msg = 0 );
637- exception( char const *function, char const *uri, CURLcode code );
638- exception( char const *function, char const *uri, CURLMcode code );
639- ~exception() throw();
640-
641- virtual const char* what() const throw();
642-
643-private:
644- std::string msg_;
645-};
646-
647-////////// create & destroy ///////////////////////////////////////////////////
648-
649-/**
650- * The signature type of cURL's write function callback.
651- */
652-typedef size_t (*write_fn_t)( void*, size_t, size_t, void* );
653-
654-/**
655- * Creates a new, initialized cURL instance.
656- *
657- * @throws exception upon failure.
658- */
659-CURL* create( char const *uri, write_fn_t fn, void *data );
660-
661-/**
662- * Destroys a cURL instance.
663- *
664- * @param instance A cURL instance. If \c NULL, does nothing.
665- */
666-void destroy( CURL *instance );
667-
668-////////// streambuf //////////////////////////////////////////////////////////
669-
670-/**
671- * A curl::streambuf is-a std::streambuf for streaming the contents of URI
672- * using cURL. However, do not use this class directly. Use uri::streambuf
673- * instead.
674- */
675-class streambuf : public std::streambuf {
676-public:
677- /**
678- * Constructs a %streambuf.
679- */
680- streambuf();
681-
682- /**
683- * Constructs a %streambuf and opens a connection to the server hosting the
684- * given URI for subsequent streaming.
685- *
686- * @param uri The URI to stream.
687- */
688- streambuf( char const *uri );
689-
690- /**
691- * Constructs a %streambuf using an existing CURL object.
692- *
693- * @param curl The CURL object to use. This %streambuf takes ownership of
694- * it.
695- */
696- streambuf( CURL *curl );
697-
698- /**
699- * Destroys a %streambuf.
700- */
701- ~streambuf();
702-
703- /**
704- * Opens a connection to the server hosting the given URI for subsequent
705- * streaming.
706- *
707- * @param uri The URI to stream.
708- * @throws exception upon failure.
709- */
710- void open( char const *uri );
711-
712- /**
713- * Tests whether the buffer is open.
714- *
715- * @return Returns \c true only if the buffer is open.
716- */
717- bool is_open() const {
718- return !!curl_;
719- }
720-
721- /**
722- * Closes this %streambuf.
723- */
724- void close();
725-
726- /**
727- * Gets the CURL object in use.
728- *
729- * @return Return said CURL object.
730- */
731- CURL* curl() const {
732- return curl_;
733- }
734-
735- /**
736- * Provide a InformDataRead that will get callbacks about read events.
737- */
738- void setInformer( http_client::InformDataRead *aInformer ) {
739- theInformer = aInformer;
740- }
741-
742- /**
743- * Specify whether this streambuf has memory ownership over the
744- * InformDataRead it has been passed. You can use this if, for example,
745- * the lifetime of the streambuf will extend past the lifetime of the
746- * object which created the InformDataRead.
747- */
748- void setOwnInformer( bool aOwnInformer ) {
749- theOwnInformer = aOwnInformer;
750- }
751-
752- int multi_perform();
753-
754-protected:
755- // inherited
756- std::streamsize showmanyc();
757- int_type underflow();
758-
759-private:
760- void curl_read();
761- static size_t curl_write_callback( void*, size_t, size_t, void* );
762-
763- void init();
764- void init_curlm();
765-
766- char *buf_;
767- std::streamsize buf_capacity_;
768- std::streamoff buf_len_;
769-
770- CURL *curl_;
771- CURLM *curlm_;
772- int curl_running_;
773- http_client::InformDataRead *theInformer;
774- bool theOwnInformer;
775-
776- // forbid
777- streambuf( streambuf const& );
778- streambuf& operator=( streambuf const& );
779-#ifdef WIN32
780- SOCKET dummy_socket_;
781-#endif /* WIN32 */
782-};
783-
784-///////////////////////////////////////////////////////////////////////////////
785-
786-} // namespace curl
787-} // namespace zorba
788-#endif /* ZORBA_CURL_UTIL_H */
789-/* vim:set et sw=2 ts=2: */
790
791=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_wrappers.h'
792--- modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_wrappers.h 2013-02-07 17:24:36 +0000
793+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/curl_wrappers.h 1970-01-01 00:00:00 +0000
794@@ -1,45 +0,0 @@
795-/*
796- * Copyright 2006-2008 The FLWOR Foundation.
797- *
798- * Licensed under the Apache License, Version 2.0 (the "License");
799- * you may not use this file except in compliance with the License.
800- * You may obtain a copy of the License at
801- *
802- * http://www.apache.org/licenses/LICENSE-2.0
803- *
804- * Unless required by applicable law or agreed to in writing, software
805- * distributed under the License is distributed on an "AS IS" BASIS,
806- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
807- * See the License for the specific language governing permissions and
808- * limitations under the License.
809- */
810-
811-#ifndef CURL_WRAPPERS_H
812-#define CURL_WRAPPERS_H
813-
814-#include <curl/curl.h>
815-#include <iostream>
816-
817-#define LOC_INFO << __FILE__ << ":" << __LINE__ << std::endl
818-
819-CURL* curl_easy_init_wrapped(const char* file, const int line);
820-
821-CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, char* char_args);
822-
823-CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, const char* args);
824-CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, void* args);
825-CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, size_t(*)(char*, size_t, size_t, void*));
826-CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, size_t(*)(void*, size_t, size_t, void*));
827-CURLcode curl_easy_setopt_wrapped(const char* file, const int line, CURL* curl, CURLoption option, int args);
828-
829-CURLMcode curl_multi_perform_wrapped(const char*file, const int line, CURLM *multi_handle, int *running_handles);
830-CURLMsg* curl_multi_info_read_wrapped(const char* file, const int line, CURLM *multi_handle, int *msgs_in_queue);
831-CURLMcode curl_multi_add_handle_wrapped(const char* file, const int line, CURLM *multi_handle, CURL *curl_handle);
832-CURLMcode curl_multi_remove_handle_wrapped(const char* file, const int line, CURLM *multi_handle, CURL *curl_handle);
833-
834-void curl_slist_free_all_wrapped(const char* file, const int line, curl_slist *list);
835-void curl_formfree_wrapped(const char*file, const int line, curl_httppost *form);
836-
837-curl_slist* curl_slist_append_wrapped(const char* file, const int line, curl_slist *list, const char *value);
838-
839-#endif // CURL_WRAPPERS_H
840
841=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/error_thrower.h'
842--- modules/com/zorba-xquery/www/modules/http-client.xq.src/error_thrower.h 2013-02-07 17:24:36 +0000
843+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/error_thrower.h 1970-01-01 00:00:00 +0000
844@@ -1,53 +0,0 @@
845-/*
846- * Copyright 2006-2008 The FLWOR Foundation.
847- *
848- * Licensed under the Apache License, Version 2.0 (the "License");
849- * you may not use this file except in compliance with the License.
850- * You may obtain a copy of the License at
851- *
852- * http://www.apache.org/licenses/LICENSE-2.0
853- *
854- * Unless required by applicable law or agreed to in writing, software
855- * distributed under the License is distributed on an "AS IS" BASIS,
856- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
857- * See the License for the specific language governing permissions and
858- * limitations under the License.
859- */
860-
861-#pragma once
862-#include <zorba/zorba.h>
863-#include <zorba/user_exception.h>
864-#include <curl/curl.h>
865-
866-namespace zorba {
867-namespace http_client {
868-
869-class ErrorThrower
870-{
871-private:
872- ItemFactory* theFactory;
873- struct curl_slist** theHeaderList;
874-
875-public:
876- ErrorThrower(ItemFactory* aFactory, struct curl_slist** aHeaderList)
877- :
878- theFactory(aFactory),
879- theHeaderList(aHeaderList)
880- {
881- }
882-
883- void raiseException( String const &aNamespace, String const &aLocalName,
884- String const &aDescription )
885- {
886- if (*theHeaderList)
887- curl_slist_free_all(*theHeaderList);
888-
889- throw USER_EXCEPTION(
890- theFactory->createQName(aNamespace, aLocalName), aDescription
891- );
892- }
893-};
894-
895-} // namespace http_client
896-} // namespace zorba
897-/* vim:set et sw=2 ts=2: */
898
899=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/http_client.cpp'
900--- modules/com/zorba-xquery/www/modules/http-client.xq.src/http_client.cpp 2013-02-07 17:24:36 +0000
901+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/http_client.cpp 1970-01-01 00:00:00 +0000
902@@ -1,256 +0,0 @@
903-/*
904- * Copyright 2006-2008 The FLWOR Foundation.
905- *
906- * Licensed under the Apache License, Version 2.0 (the "License");
907- * you may not use this file except in compliance with the License.
908- * You may obtain a copy of the License at
909- *
910- * http://www.apache.org/licenses/LICENSE-2.0
911- *
912- * Unless required by applicable law or agreed to in writing, software
913- * distributed under the License is distributed on an "AS IS" BASIS,
914- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
915- * See the License for the specific language governing permissions and
916- * limitations under the License.
917- */
918-#include <curl/curl.h>
919-#include <map>
920-#include <zorba/zorba.h>
921-#include <zorba/serializer.h>
922-#include <zorba/external_module.h>
923-#include <zorba/function.h>
924-#include <zorba/empty_sequence.h>
925-#include <zorba/user_exception.h>
926-
927-#include "http_request_handler.h"
928-#include "request_parser.h"
929-#include "http_response_handler.h"
930-#include "http_response_parser.h"
931-
932-#ifdef WIN32
933-# include <Windows.h>
934-# define MAX_BUF_SIZE 2048
935-#endif
936-
937-namespace zorba {
938-
939- namespace http_client {
940-#ifdef WIN32
941- static void set_cacert(CURL* lCurl, std::string aPath) {
942- TCHAR path[MAX_BUF_SIZE];
943- int r = GetModuleFileName(NULL, path, 2048);
944- if (r == -1)
945- return;
946-# ifdef UNICODE
947- char buf[MAX_BUF_SIZE];
948- memset(buf, 0, MAX_BUF_SIZE);
949- for (int i = 0; i <= r; ++i) {
950- buf[i] = (char) path[i];
951- }
952- std::string lPath(buf);
953-# else
954- std::string lPath(path);
955-# endif
956- aPath = lPath.substr(0, lPath.rfind('\\'));
957- aPath += "\\cacert.pem";
958- if(GetFileAttributesA(aPath.c_str()) != INVALID_FILE_ATTRIBUTES)
959- curl_easy_setopt(lCurl, CURLOPT_CAINFO, aPath.c_str());
960- else
961- curl_easy_setopt(lCurl, CURLOPT_SSL_VERIFYPEER, 0L);
962- }
963-#endif //WIN32
964-
965- class HttpSendFunction : public ContextualExternalFunction {
966- protected:
967- const ExternalModule* theModule;
968- ItemFactory* theFactory;
969-
970- public:
971- HttpSendFunction(const ExternalModule* aModule)
972- : theModule(aModule),
973- theFactory(Zorba::getInstance(0)->getItemFactory()) {}
974-
975- virtual ~HttpSendFunction() {}
976-
977- public:
978- virtual String
979- getURI() const { return theModule->getURI(); }
980-
981- virtual String
982- getLocalName() const { return "http-sequential-impl"; }
983-
984- virtual ItemSequence_t
985- evaluate(const ExternalFunction::Arguments_t& args,
986- const StaticContext* aStaticContext, const DynamicContext* aDynamicContext)
987- const;
988- };
989-
990- class HttpReadFunction : public HttpSendFunction {
991- public:
992- HttpReadFunction(const ExternalModule* aModule)
993- : HttpSendFunction(aModule) {}
994-
995- virtual ~HttpReadFunction() {}
996-
997- public:
998- virtual String
999- getLocalName() const { return "http-nondeterministic-impl"; }
1000-
1001- };
1002-
1003- class HttpClientModule : public ExternalModule {
1004- protected:
1005- class ltstr
1006- {
1007- public:
1008- bool operator()(const String& s1, const String& s2) const
1009- {
1010- return s1.compare(s2) < 0;
1011- }
1012- };
1013-
1014- typedef std::map<String, ExternalFunction*, ltstr> FuncMap_t;
1015-
1016- FuncMap_t theFunctions;
1017-
1018- public:
1019- virtual ~HttpClientModule();
1020-
1021- HttpClientModule() : theModuleUri("http://www.zorba-xquery.com/modules/http-client")
1022- {
1023- for (FuncMap_t::const_iterator lIter = theFunctions.begin();
1024- lIter != theFunctions.end(); ++lIter) {
1025- delete lIter->second;
1026- }
1027- theFunctions.clear();
1028- }
1029-
1030- virtual String
1031- getURI() const { return theModuleUri; }
1032-
1033- virtual ExternalFunction*
1034- getExternalFunction(const String& aLocalname)
1035- {
1036- ExternalFunction*& lFunc = theFunctions[aLocalname];
1037- if (!lFunc) {
1038- if (aLocalname == "http-sequential-impl") {
1039- lFunc = new HttpSendFunction(this);
1040- } else if (aLocalname == "http-nondeterministic-impl") {
1041- lFunc = new HttpReadFunction(this);
1042- }
1043- }
1044- return lFunc;
1045- }
1046-
1047- virtual void
1048- destroy()
1049- {
1050- if (!dynamic_cast<HttpClientModule*>(this)) {
1051- return;
1052- }
1053- delete this;
1054- }
1055-
1056- private:
1057- String theModuleUri;
1058- };
1059-
1060- ItemSequence_t
1061- general_evaluate(
1062- const ExternalFunction::Arguments_t& args,
1063- const StaticContext* aStaticContext,
1064- const DynamicContext* aDynamicContext,
1065- ItemFactory* aFactory)
1066- {
1067- CURL* lCURL = curl_easy_init();
1068-
1069- Item lRequest;
1070- Item lHref;
1071- Item lContent;
1072-
1073- Iterator_t arg0_iter = args[0]->getIterator();
1074- arg0_iter->open();
1075- bool lReqSet = arg0_iter->next(lRequest);
1076- arg0_iter->close();
1077- Iterator_t arg1_iter = args[1]->getIterator();
1078- arg1_iter->open();
1079- bool lHrefSet = arg1_iter->next(lHref);
1080- arg1_iter->close();
1081-
1082- std::string lData;
1083-
1084- std::auto_ptr<HttpRequestHandler> lHandler;
1085- std::auto_ptr<RequestParser> lParser;
1086- struct curl_slist* lHeaderList = 0;
1087-
1088- ErrorThrower thrower(aFactory, &lHeaderList);
1089-
1090- if (lReqSet) {
1091- lHandler.reset(new HttpRequestHandler(lCURL, args[2]));
1092- lParser.reset(new RequestParser(lHandler.get(), thrower));
1093- lParser->parse(lRequest);
1094- }
1095- if (lHrefSet) {
1096- curl_easy_setopt(lCURL, CURLOPT_URL, lHref.getStringValue().c_str());
1097- }
1098- curl_easy_setopt(lCURL, CURLOPT_USERAGENT, "libcurl-agent/1.0");
1099- //curl_easy_setopt(lCURL, CURLOPT_PROXY, "localhost:8888");
1100-#ifdef WIN32
1101- std::string caCertPath;
1102- set_cacert(lCURL, caCertPath);
1103-#endif
1104- HttpResponseHandler lRespHandler(aFactory, lHeaderList);
1105- String lOverrideContentType;
1106- if (lHandler.get())
1107- lHandler->getOverrideContentType(lOverrideContentType);
1108- bool lStatusOnly =
1109- lHandler.get() == NULL ? false : (lHandler->isStatusOnly() || lHandler->isHeadRequest());
1110- // This gives the ownership of lCurl to the HttpResponseParser
1111- std::auto_ptr<HttpResponseParser> lRespParser(new HttpResponseParser(lRespHandler, lCURL, thrower,
1112- lOverrideContentType.c_str(), lStatusOnly));
1113- int lRetCode = lRespParser->parse();
1114-
1115- if (lRetCode) {
1116- thrower.raiseException("http://expath.org/ns/error", "HC001", "An HTTP error occurred");
1117- }
1118-
1119- // If the Parser is "self contained", that means it didn't create any
1120- // objects with a lifecycle longer than itself; therefore we should free
1121- // it (by letting auto_ptr delete it). If the Parser is not self contained,
1122- // then it will have arranged for some other memory manager to free it
1123- // later when appropriate; therefore we should NOT let auto_ptr delete it
1124- // now.
1125- if ( ! lRespParser->selfContained()) {
1126- lRespParser.release();
1127- }
1128- return ItemSequence_t(lRespHandler.releaseResult());
1129- }
1130-
1131- ItemSequence_t
1132- HttpSendFunction::evaluate(const ExternalFunction::Arguments_t& args,
1133- const StaticContext* aStaticContext, const DynamicContext* aDynamicContext) const
1134- {
1135- return general_evaluate(args, aStaticContext, aDynamicContext, theFactory);
1136- }
1137-
1138- HttpClientModule::~HttpClientModule()
1139- {
1140- for (FuncMap_t::const_iterator lIter = theFunctions.begin();
1141- lIter != theFunctions.end(); ++lIter) {
1142- delete lIter->second;
1143- }
1144- theFunctions.clear();
1145- }
1146- } // namespace http_request
1147-} // namespace zorba
1148-
1149-#ifdef WIN32
1150-# define DLL_EXPORT __declspec(dllexport)
1151-#else
1152-# define DLL_EXPORT __attribute__ ((visibility("default")))
1153-#endif
1154-
1155-extern "C" DLL_EXPORT zorba::ExternalModule* createModule() {
1156- return new zorba::http_client::HttpClientModule();
1157-}
1158-
1159
1160=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/http_request_handler.cpp'
1161--- modules/com/zorba-xquery/www/modules/http-client.xq.src/http_request_handler.cpp 2013-06-12 13:26:15 +0000
1162+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/http_request_handler.cpp 1970-01-01 00:00:00 +0000
1163@@ -1,292 +0,0 @@
1164-/*
1165- * Copyright 2006-2008 The FLWOR Foundation.
1166- *
1167- * Licensed under the Apache License, Version 2.0 (the "License");
1168- * you may not use this file except in compliance with the License.
1169- * You may obtain a copy of the License at
1170- *
1171- * http://www.apache.org/licenses/LICENSE-2.0
1172- *
1173- * Unless required by applicable law or agreed to in writing, software
1174- * distributed under the License is distributed on an "AS IS" BASIS,
1175- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1176- * See the License for the specific language governing permissions and
1177- * limitations under the License.
1178- */
1179-
1180-#include <iostream>
1181-
1182-#include <zorba/api_shared_types.h>
1183-#include <zorba/serializer.h>
1184-#include <zorba/singleton_item_sequence.h>
1185-#include <zorba/util/base64_util.h>
1186-#include <zorba/xquery_functions.h>
1187-#include <zorba/zorba.h>
1188-#include <zorba/zorba_functions.h>
1189-
1190-#include "http_request_handler.h"
1191-
1192-namespace zorba { namespace http_client {
1193-
1194- HttpRequestHandler::HttpRequestHandler(CURL* aCurl,
1195- ItemSequence* aContent)
1196- : theCurl(aCurl),
1197- theStatusOnly(false),
1198- theInsideMultipart(false),
1199- theLastBodyHadContent(false),
1200- theContent(aContent),
1201- theSerStream(NULL),
1202- thePost(NULL),
1203- theLast(NULL),
1204- theIsHeadRequest(false)
1205- {
1206- theHeaderLists.push_back(NULL);
1207- }
1208-
1209- HttpRequestHandler::~HttpRequestHandler()
1210- {
1211- std::vector<struct curl_slist*>::iterator lIter;
1212- for (lIter = theHeaderLists.begin(); lIter != theHeaderLists.end(); ++lIter)
1213- {
1214- if (*lIter) {
1215- curl_slist_free_all(*lIter);
1216- }
1217- }
1218-
1219- if (thePost != NULL) {
1220- curl_formfree(thePost);
1221- }
1222- delete theSerStream;
1223- }
1224-
1225- void HttpRequestHandler::begin()
1226- {
1227- }
1228-
1229- void HttpRequestHandler::beginResponse(int aStatus, String aMessage)
1230- {
1231- }
1232-
1233- void HttpRequestHandler::endResponse()
1234- {
1235- }
1236-
1237- void HttpRequestHandler::beginRequest(String aMethod,
1238- String href,
1239- bool aStatusOnly,
1240- String aUsername,
1241- String aPassword,
1242- String aAuthMethod,
1243- bool aSendAuthorization,
1244- String aOverrideContentType,
1245- bool aFollowRedirect,
1246- int aTimeout /*= -1*/ )
1247- {
1248- aMethod = fn::upper_case(aMethod);
1249- const char* lStr = aMethod.c_str();
1250- theMethodString = lStr;
1251- String const lAuthMethod = fn::lower_case(aAuthMethod);
1252- if (theMethodString == "HEAD" || theMethodString == "OPTIONS") {
1253- curl_easy_setopt(theCurl, CURLOPT_NOBODY, 1L);
1254- theIsHeadRequest = true;
1255- }
1256- curl_easy_setopt(theCurl, CURLOPT_CUSTOMREQUEST, theMethodString.c_str());
1257- if (href != "") {
1258- curl_easy_setopt(theCurl, CURLOPT_URL, href.c_str());
1259- }
1260- if (aFollowRedirect) {
1261- curl_easy_setopt(theCurl, CURLOPT_FOLLOWLOCATION, 1);
1262- }
1263- theStatusOnly = aStatusOnly;
1264- theOverrideContentType = aOverrideContentType;
1265- if (aTimeout != -1) {
1266- curl_easy_setopt(theCurl, CURLOPT_TIMEOUT, aTimeout);
1267- }
1268- if (aUsername != "" && !aSendAuthorization) {
1269- String lUserPw = aUsername + ":" + aPassword;
1270- theUserPW = lUserPw.c_str();
1271- curl_easy_setopt(theCurl, CURLOPT_USERPWD, theUserPW.c_str());
1272- if (lAuthMethod == "basic") {
1273- curl_easy_setopt(theCurl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
1274- } else if (lAuthMethod == "digest") {
1275- curl_easy_setopt(theCurl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
1276- }
1277- }
1278- if (aUsername != "" && aSendAuthorization) {
1279- if (lAuthMethod == "basic") {
1280- String lAuthString = aUsername + ":" + aPassword;
1281- String lAuth = "Authorization: Basic ";
1282- lAuth += base64::encode(lAuthString);
1283- theAuthMethod = lAuth.c_str();
1284- theHeaderLists[0] = curl_slist_append(theHeaderLists[0], theAuthMethod.c_str());
1285- } else if (lAuthMethod == "digest") {
1286- String lUserPw = aUsername + ":" + aPassword;
1287- theUserPW = lUserPw.c_str();
1288- curl_easy_setopt(theCurl, CURLOPT_USERPWD, theUserPW.c_str());
1289- curl_easy_setopt(theCurl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
1290- }
1291- }
1292- }
1293-
1294- void HttpRequestHandler::endRequest()
1295- {
1296- }
1297-
1298- void HttpRequestHandler::header(String aName, String aValue)
1299- {
1300- std::string lValue = aName.c_str();
1301- lValue += ":";
1302- lValue += aValue.c_str();
1303- theHeaderStrings.push_back(lValue);
1304- if (!theInsideMultipart) {
1305- theHeaderLists[0] = curl_slist_append(theHeaderLists[0], lValue.c_str());
1306- } else {
1307- if (aName == "Content-Disposition") {
1308- Sequence<String> lTokens(fn::tokenize(aValue, ";"));
1309- for (String lNextToken; lTokens.next( &lNextToken );) {
1310- std::pair<String, String> lKeyValue = twinSplit(lNextToken);
1311- if (lKeyValue.first == "name") {
1312- theMultipartName = lKeyValue.second;
1313- zfn::trim(theMultipartName, "\"\'");
1314- }
1315- else if (lKeyValue.first == "filename") {
1316- theMultiPartFileName = lKeyValue.second;
1317- zfn::trim(theMultiPartFileName, "\"\'");
1318- }
1319- }
1320- } else {
1321- theHeaderLists.back() = curl_slist_append(theHeaderLists.back(), (lValue).c_str());
1322- }
1323- }
1324- }
1325-
1326- void HttpRequestHandler::beginBody(String aContentType,
1327- String aSrc,
1328- ItemSequence* aSerializerOptions)
1329- {
1330- theLastSerializerOptions = aSerializerOptions;
1331- theSerStream = new std::ostringstream();
1332- theCurrentContentType = aContentType;
1333- theContentType = "Content-Type: ";
1334- theContentType += aContentType.c_str();
1335- if (!theInsideMultipart) {
1336- theHeaderLists[0] = curl_slist_append(theHeaderLists[0], theContentType.c_str());
1337- } else {
1338- theHeaderLists.back() = curl_slist_append(theHeaderLists.back(), theContentType.c_str());
1339- }
1340- }
1341-
1342- void HttpRequestHandler::any(Item aItem)
1343- {
1344- serializeItem(aItem);
1345- }
1346-
1347- void HttpRequestHandler::endBody()
1348- {
1349- if (!theLastBodyHadContent) {
1350- if (theContent == NULL) {
1351- cleanUpBody();
1352- return;
1353- }
1354- Item lItem;
1355- Iterator_t content_iter = theContent->getIterator();
1356- content_iter->open();
1357- while (content_iter->next(lItem)) {
1358- serializeItem(lItem);
1359- }
1360- content_iter->close();
1361- }
1362- thePostDataString = theSerStream->str();
1363- thePostData = thePostDataString.c_str();
1364- if (!theInsideMultipart) {
1365- curl_easy_setopt(theCurl, CURLOPT_POSTFIELDSIZE, thePostDataString.length());
1366- curl_easy_setopt(theCurl, CURLOPT_POSTFIELDS, thePostData);
1367- } else {
1368- if (theMultiPartFileName == "")
1369- curl_formadd(&thePost, &theLast,
1370- CURLFORM_COPYNAME, theMultipartName.c_str(),
1371- CURLFORM_COPYCONTENTS, thePostData,
1372- CURLFORM_CONTENTSLENGTH, thePostDataString.length(),
1373- CURLFORM_CONTENTHEADER, theHeaderLists.back(),
1374- CURLFORM_END);
1375- else
1376- curl_formadd(&thePost, &theLast,
1377- CURLFORM_COPYNAME, theMultipartName.c_str(),
1378- CURLFORM_BUFFER, theMultiPartFileName.c_str(),
1379- CURLFORM_BUFFERPTR, thePostData,
1380- CURLFORM_BUFFERLENGTH, thePostDataString.length(),
1381- CURLFORM_CONTENTHEADER, theHeaderLists.back(),
1382- CURLFORM_END);
1383- theHeaderLists.push_back(NULL);
1384- }
1385- }
1386-
1387- void HttpRequestHandler::beginMultipart(String aContentType, String aBoundary)
1388- {
1389- theMultiPartFileName = "";
1390- theMultipartName = "zorba-default";
1391- theInsideMultipart = true;
1392- std::string lValue = "Content-Type: ";
1393- lValue += aContentType.c_str();
1394- theHeaderStrings.push_back (lValue);
1395- theHeaderLists[0] = curl_slist_append(theHeaderLists[0], lValue.c_str());
1396- theHeaderLists.push_back(NULL);
1397- }
1398-
1399- void HttpRequestHandler::endMultipart()
1400- {
1401- theInsideMultipart = false;
1402- curl_easy_setopt(theCurl, CURLOPT_HTTPPOST, thePost);
1403- }
1404-
1405- void HttpRequestHandler::end()
1406- {
1407- if (theHeaderLists[0]) {
1408- curl_easy_setopt(theCurl, CURLOPT_HTTPHEADER, theHeaderLists[0]);
1409- }
1410- }
1411-
1412- bool HttpRequestHandler::getOverrideContentType( String& aResult )
1413- {
1414- if (theOverrideContentType == "") {
1415- return false;
1416- }
1417- aResult = theOverrideContentType;
1418- return true;
1419- }
1420-
1421- void HttpRequestHandler::cleanUpBody()
1422- {
1423- delete theSerStream;
1424- theSerStream = 0;
1425- theLastBodyHadContent = false;
1426- }
1427-
1428- void HttpRequestHandler::serializeItem( Item aItem )
1429- {
1430- theLastBodyHadContent = true;
1431- Serializer_t lSerializer =
1432- Serializer::createSerializer(theLastSerializerOptions);
1433- SingletonItemSequence lSequence(aItem);
1434- lSerializer->serialize(&lSequence, *theSerStream);
1435- }
1436-
1437- std::pair<String, String>
1438- HttpRequestHandler::twinSplit(const String& aStr)
1439- {
1440- String lKey, lValue;
1441-
1442- String::size_type const equals = aStr.find('=');
1443- if (equals != String::npos) {
1444- lKey = aStr.substr(0, equals);
1445- lValue = aStr.substr(equals + 1);
1446- zfn::trim(lKey);
1447- zfn::trim(lValue);
1448- }
1449-
1450- return std::pair<String, String>(lKey, lValue);
1451- }
1452-
1453-} // namespace http_client
1454-} // namespace zorba
1455-/* vim:set et sw=2 ts=2: */
1456
1457=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/http_request_handler.h'
1458--- modules/com/zorba-xquery/www/modules/http-client.xq.src/http_request_handler.h 2013-02-07 17:24:36 +0000
1459+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/http_request_handler.h 1970-01-01 00:00:00 +0000
1460@@ -1,113 +0,0 @@
1461-/*
1462- * Copyright 2006-2008 The FLWOR Foundation.
1463- *
1464- * Licensed under the Apache License, Version 2.0 (the "License");
1465- * you may not use this file except in compliance with the License.
1466- * You may obtain a copy of the License at
1467- *
1468- * http://www.apache.org/licenses/LICENSE-2.0
1469- *
1470- * Unless required by applicable law or agreed to in writing, software
1471- * distributed under the License is distributed on an "AS IS" BASIS,
1472- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1473- * See the License for the specific language governing permissions and
1474- * limitations under the License.
1475- */
1476-#ifndef HTTP_REQUEST_HANDLER_H
1477-#define HTTP_REQUEST_HANDLER_H
1478-
1479-#include <sstream>
1480-#include <vector>
1481-
1482-#include <curl/curl.h>
1483-#include <zorba/zorba.h>
1484-
1485-#include "request_handler.h"
1486-
1487-namespace zorba { namespace http_client {
1488-
1489- class HttpRequestHandler : public RequestHandler {
1490- private:
1491- CURL* theCurl;
1492- bool theStatusOnly;
1493- String theOverrideContentType;
1494- bool theInsideMultipart;
1495- std::vector<struct curl_slist*> theHeaderLists;
1496- bool theLastBodyHadContent;
1497- ItemSequence* theContent;
1498- std::ostringstream* theSerStream;
1499- struct curl_httppost* thePost;
1500- struct curl_httppost* theLast;
1501- String theCurrentContentType;
1502- ItemSequence* theLastSerializerOptions;
1503- std::string thePostDataString;
1504- const char* thePostData;
1505- long thePostDataSize;
1506- String theMultipartName;
1507- String theMultiPartFileName;
1508- // saved strings which won't be copied by curl
1509- std::string theMethodString;
1510- std::string theUserPW;
1511- std::string theAuthMethod;
1512- std::vector<std::string> theHeaderStrings;
1513- std::string theContentType;
1514- bool theIsHeadRequest;
1515-
1516- public: //Constructions
1517- HttpRequestHandler(CURL* aCurl,
1518- ItemSequence* aContent);
1519- virtual ~HttpRequestHandler();
1520-
1521- public: //Interfaces
1522- /**
1523- * @brief Get the override-content-type option.
1524- *
1525- * If the user set the override-content-type option, this method will
1526- * set the result to the user specified value and will return true.
1527- * Otherwise it will return false.
1528- *
1529- * @param aResult The override-content-type option, if set.
1530- * @return A boolean indicating if the override-content-type is set.
1531- */
1532- bool getOverrideContentType(String& aResult);
1533-
1534- public: //Implementation of parent interface
1535- virtual void begin();
1536- virtual void beginResponse(int aStatus, String aMessage);
1537- virtual void endResponse();
1538- virtual void beginRequest(
1539- String aMethod,
1540- String href,
1541- bool aStatusOnly,
1542- String aUsername,
1543- String aPassword,
1544- String aAuthMethod,
1545- bool aSendAuthorization,
1546- String aOverrideContentType,
1547- bool aFollowRedirect,
1548- int aTimeout = -1);
1549- virtual void endRequest();
1550- virtual void header(String aName, String aValue);
1551- virtual void beginBody(
1552- String aContentType,
1553- String aSrc,
1554- ItemSequence* aSerializerOptions);
1555- virtual void any(Item aItem);
1556-
1557- void serializeItem( Item aItem );
1558- virtual void endBody();
1559- virtual void beginMultipart(String aContentType, String aBoundary);
1560- virtual void endMultipart();
1561- virtual void end();
1562-
1563- bool isStatusOnly() const { return theStatusOnly; }
1564- virtual bool isHeadRequest() const { return theIsHeadRequest; }
1565-
1566- private: //Helper functions
1567- void cleanUpBody();
1568- static std::pair<String, String> twinSplit(const String& aStr);
1569- };
1570-
1571-}}
1572-
1573-#endif //HTTP_REQUEST_HANDLER_H
1574
1575=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_handler.cpp'
1576--- modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_handler.cpp 2013-02-07 17:24:36 +0000
1577+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_handler.cpp 1970-01-01 00:00:00 +0000
1578@@ -1,232 +0,0 @@
1579-/*
1580- * Copyright 2006-2008 The FLWOR Foundation.
1581- *
1582- * Licensed under the Apache License, Version 2.0 (the "License");
1583- * you may not use this file except in compliance with the License.
1584- * You may obtain a copy of the License at
1585- *
1586- * http://www.apache.org/licenses/LICENSE-2.0
1587- *
1588- * Unless required by applicable law or agreed to in writing, software
1589- * distributed under the License is distributed on an "AS IS" BASIS,
1590- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1591- * See the License for the specific language governing permissions and
1592- * limitations under the License.
1593- */
1594-
1595-#include <zorba/xquery_exception.h>
1596-#include <zorba/item.h>
1597-#include <zorba/item_factory.h>
1598-#include <zorba/zorba_string.h>
1599-
1600-#include "http_response_handler.h"
1601-#include "http_response_parser.h"
1602-
1603-namespace zorba { namespace http_client {
1604-
1605- //////////////////////////////////////////////////////////////////////////
1606- // HttpResponseIterator
1607- //////////////////////////////////////////////////////////////////////////
1608-
1609- const char* theNamespace = "http://expath.org/ns/http-client";
1610-
1611- HttpResponseIterator::HttpResponseIterator(curl_slist* aHeaderList)
1612- : theResponseSet(false), theHeaderList(aHeaderList)
1613- {
1614- // Set an empty item as the response item
1615- theItems.push_back(Item());
1616- }
1617-
1618- HttpResponseIterator::~HttpResponseIterator()
1619- {
1620- if (theHeaderList)
1621- curl_slist_free_all(theHeaderList);
1622- }
1623-
1624- Iterator_t HttpResponseIterator::getIterator()
1625- {
1626- return new InternalIterator(this);
1627- }
1628-
1629- HttpResponseIterator::InternalIterator::InternalIterator(HttpResponseIterator *item_sequence) :
1630- theItemSequence(item_sequence),
1631- theIndex(0)
1632- {
1633- is_open = false;
1634- }
1635-
1636- void HttpResponseIterator::InternalIterator::open()
1637- {
1638- theIndex = 0;
1639- is_open = true;
1640- }
1641-
1642- void HttpResponseIterator::InternalIterator::close()
1643- {
1644- is_open = false;
1645- }
1646-
1647- bool HttpResponseIterator::InternalIterator::isOpen() const
1648- {
1649- return is_open;
1650- }
1651-
1652- bool HttpResponseIterator::InternalIterator::next( Item& aItem )
1653- {
1654- if (!theItemSequence->theResponseSet) {
1655- return false;
1656- }
1657- if (theIndex < theItemSequence->theItems.size()) {
1658- aItem = theItemSequence->theItems[theIndex];
1659- ++theIndex;
1660- return !aItem.isNull();
1661- }
1662- return false;
1663- }
1664-
1665- void HttpResponseIterator::addItem(const Item& aItem)
1666- {
1667- theItems.push_back(aItem);
1668- }
1669-
1670- void HttpResponseIterator::setResponseItem(const Item& aItem)
1671- {
1672- theItems[0] = aItem;
1673- theResponseSet = true;
1674- }
1675-
1676- //////////////////////////////////////////////////////////////////////////
1677- // HttpResponseHandler
1678- //////////////////////////////////////////////////////////////////////////
1679-
1680- HttpResponseHandler::HttpResponseHandler(ItemFactory* aFactory, curl_slist* aHeaderList)
1681- :
1682- theResult(new HttpResponseIterator(aHeaderList)),
1683- theFactory(aFactory),
1684- theIsInsideMultipart(false),
1685- theDeleteResponse(true)
1686- {
1687- theUntypedQName = theFactory->createQName("http://www.w3.org/2001/XMLSchema", "untyped");
1688- }
1689-
1690- HttpResponseHandler::~HttpResponseHandler() {
1691- if (theDeleteResponse) {
1692- delete theResult;
1693- }
1694- }
1695-
1696- void HttpResponseHandler::begin()
1697- {
1698- }
1699-
1700- void HttpResponseHandler::beginResponse(int aStatus, String aMessage)
1701- {
1702- Item lNullParent;
1703- Item lNullType;
1704- String lLocalName = "response";
1705- Item lNodeName = theFactory->createQName(theNamespace, lLocalName);
1706- theResponse = theFactory->createElementNode(lNullParent, lNodeName,
1707- theUntypedQName, true, false, NsBindings());
1708- theFactory->createAttributeNode(theResponse,
1709- theFactory->createQName("", "status"), lNullType,
1710- theFactory->createInteger(aStatus));
1711- theFactory->createAttributeNode(theResponse,
1712- theFactory->createQName("", "message"), lNullType,
1713- theFactory->createString(aMessage));
1714- theResult->setResponseItem(theResponse);
1715- }
1716-
1717- void HttpResponseHandler::endResponse()
1718- {
1719- }
1720-
1721- // Since this class is only used to handle responses, beginRequest and
1722- // endRequest are not implemented.
1723- void HttpResponseHandler::beginRequest(String aMethod,
1724- String href,
1725- bool aStatusOnly,
1726- String aUsername,
1727- String aPassword,
1728- String aAuthMethod,
1729- bool aSendAuthorization,
1730- String aOverrideContentType,
1731- bool aFollowRedirect,
1732- int aTimeout /*= -1*/)
1733- {
1734- }
1735-
1736- void HttpResponseHandler::endRequest()
1737- {
1738- }
1739-
1740- void HttpResponseHandler::header(String aName, String aValue)
1741- {
1742- Item lParent = theIsInsideMultipart ? theMultipart : theResponse;
1743- Item lNullType;
1744- Item lElem = theFactory->createElementNode(lParent,
1745- theFactory->createQName(theNamespace, "header"), theUntypedQName, true,
1746- true, NsBindings());
1747- theFactory->createAttributeNode(lElem, theFactory->createQName("", "name"),
1748- lNullType, theFactory->createString(aName));
1749- theFactory->createAttributeNode(lElem, theFactory->createQName("", "value"),
1750- lNullType, theFactory->createString(aValue));
1751- }
1752-
1753- void HttpResponseHandler::beginBody(String aContentType,
1754- String aSrc,
1755- ItemSequence* aSerializerOptions)
1756- {
1757- Item lParent = theIsInsideMultipart ? theMultipart : theResponse;
1758- Item lNullType;
1759- Item lElem = theFactory->createElementNode(lParent,
1760- theFactory->createQName(theNamespace, "body"), theUntypedQName, true,
1761- true, NsBindings());
1762- theFactory->createAttributeNode(lElem,
1763- theFactory->createQName("", "media-type"),
1764- lNullType, theFactory->createString(aContentType));
1765- }
1766-
1767- void HttpResponseHandler::any(Item aItem)
1768- {
1769- theResult->addItem(aItem);
1770- }
1771-
1772- void HttpResponseHandler::endBody()
1773- {
1774- }
1775-
1776- void HttpResponseHandler::beginMultipart(String aContentType, String aBoundary)
1777- {
1778- theIsInsideMultipart = true;
1779- Item lNullType;
1780- Item lElem = theFactory->createElementNode(theResponse,
1781- theFactory->createQName(theNamespace, "body"), theUntypedQName, true,
1782- true, NsBindings());
1783- theFactory->createAttributeNode(lElem,
1784- theFactory->createQName("", "content-type"),
1785- lNullType, theFactory->createString(aContentType));
1786- theFactory->createAttributeNode(lElem,
1787- theFactory->createQName("", "boundary"),
1788- lNullType, theFactory->createString(aBoundary));
1789- }
1790-
1791- void HttpResponseHandler::endMultipart()
1792- {
1793- theIsInsideMultipart = false;
1794- }
1795-
1796- void HttpResponseHandler::end()
1797- {
1798- }
1799-
1800- HttpResponseIterator* HttpResponseHandler::getResult()
1801- {
1802- return theResult;
1803- }
1804-
1805- HttpResponseIterator* HttpResponseHandler::releaseResult()
1806- {
1807- theDeleteResponse = false;
1808- return theResult;
1809- }
1810-}} //namespace zorba, namespace http_client
1811
1812=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_handler.h'
1813--- modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_handler.h 2013-02-07 17:24:36 +0000
1814+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_handler.h 1970-01-01 00:00:00 +0000
1815@@ -1,115 +0,0 @@
1816-/*
1817- * Copyright 2006-2008 The FLWOR Foundation.
1818- *
1819- * Licensed under the Apache License, Version 2.0 (the "License");
1820- * you may not use this file except in compliance with the License.
1821- * You may obtain a copy of the License at
1822- *
1823- * http://www.apache.org/licenses/LICENSE-2.0
1824- *
1825- * Unless required by applicable law or agreed to in writing, software
1826- * distributed under the License is distributed on an "AS IS" BASIS,
1827- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1828- * See the License for the specific language governing permissions and
1829- * limitations under the License.
1830- */
1831-#ifndef HTTP_RESPONSE_HANDLER_H
1832-#define HTTP_RESPONSE_HANDLER_H
1833-
1834-#include <vector>
1835-#include <map>
1836-#include <curl/curl.h>
1837-
1838-#include <zorba/item_sequence.h>
1839-#include <zorba/iterator.h>
1840-
1841-#include "request_handler.h"
1842-
1843-namespace zorba {
1844-class Item;
1845-class ItemFactory;
1846-namespace http_client {
1847- class HttpResponseParser;
1848-
1849- class HttpResponseIterator : public ItemSequence {
1850- class InternalIterator : public Iterator
1851- {
1852- private:
1853- HttpResponseIterator* theItemSequence;
1854- std::vector<Item>::size_type theIndex;
1855- bool is_open;
1856- public:
1857- InternalIterator(HttpResponseIterator *item_sequence);
1858-
1859- virtual void open();
1860- virtual bool next(Item& aItem);
1861- virtual void close();
1862- virtual bool isOpen() const;
1863- };
1864- private:
1865- std::vector<Item> theItems;
1866- bool theResponseSet;
1867- public:
1868- HttpResponseIterator(curl_slist* aHeaderList);
1869- virtual ~HttpResponseIterator();
1870-
1871- public:
1872- virtual Iterator_t getIterator();
1873-
1874- public: //Implementation specific functions
1875- void addItem(const Item& aItem);
1876- void setResponseItem(const Item& aItem);
1877-
1878- public:
1879- static void streamReleaser(std::istream* aStream);
1880-
1881- private:
1882- curl_slist* theHeaderList;
1883- };
1884-
1885- class HttpResponseHandler : public RequestHandler {
1886- private:
1887- HttpResponseIterator* theResult;
1888- Item theResponse;
1889- Item theMultipart;
1890- ItemFactory* theFactory;
1891- bool theIsInsideMultipart;
1892- bool theDeleteResponse;
1893- Item theUntypedQName;
1894- public:
1895- HttpResponseHandler(ItemFactory* aFactory, curl_slist* theHeaderList);
1896- virtual ~HttpResponseHandler();
1897- public:
1898- HttpResponseIterator* getResult();
1899- HttpResponseIterator* releaseResult();
1900- public: //Interface implementation
1901- virtual void begin();
1902- virtual void beginResponse(int aStatus, String aMessage);
1903- virtual void endResponse();
1904- virtual void beginRequest(
1905- String aMethod,
1906- String href,
1907- bool aStatusOnly,
1908- String aUsername,
1909- String aPassword,
1910- String aAuthMethod,
1911- bool aSendAuthorization,
1912- String aOverrideContentType,
1913- bool aFollowRedirect,
1914- int aTimeout = -1);
1915- virtual void endRequest();
1916- virtual void header(String aName, String aValue);
1917- virtual void beginBody(
1918- String aContentType,
1919- String aSrc,
1920- ItemSequence* aSerializerOptions);
1921- virtual void any(Item aItem);
1922- virtual void endBody();
1923- virtual void beginMultipart(String aContentType, String aBoundary);
1924- virtual void endMultipart();
1925- virtual void end();
1926- virtual bool isHeadRequest() const { return false; }
1927- };
1928-}} //namespace zorba, namespace http_client
1929-
1930-#endif //HTTP_RESPONSE_HANDLER_H
1931
1932=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_parser.cpp'
1933--- modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_parser.cpp 2013-06-28 03:52:18 +0000
1934+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_parser.cpp 1970-01-01 00:00:00 +0000
1935@@ -1,351 +0,0 @@
1936-/*
1937- * Copyright 2006-2008 The FLWOR Foundation.
1938- *
1939- * Licensed under the Apache License, Version 2.0 (the "License");
1940- * you may not use this file except in compliance with the License.
1941- * You may obtain a copy of the License at
1942- *
1943- * http://www.apache.org/licenses/LICENSE-2.0
1944- *
1945- * Unless required by applicable law or agreed to in writing, software
1946- * distributed under the License is distributed on an "AS IS" BASIS,
1947- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1948- * See the License for the specific language governing permissions and
1949- * limitations under the License.
1950- */
1951-
1952-#include <cassert>
1953-#include <cstring>
1954-#include <iostream>
1955-#include <sstream>
1956-#include <stdexcept>
1957-#include <string>
1958-
1959-#include <zorba/config.h>
1960-#include <zorba/diagnostic_list.h>
1961-#include <zorba/error.h>
1962-#include <zorba/item.h>
1963-#include <zorba/item_factory.h>
1964-#include <zorba/util/base64_util.h>
1965-#include <zorba/util/transcode_stream.h>
1966-#include <zorba/xmldatamanager.h>
1967-#include <zorba/xquery_exception.h>
1968-#include <zorba/xquery_exception.h>
1969-#include <zorba/xquery_functions.h>
1970-
1971-#include "http_response_parser.h"
1972-#include "http_request_handler.h"
1973-#include "curl_stream_buffer.h"
1974-
1975-namespace zorba {
1976-
1977-static void parse_content_type( std::string const &s, std::string *mime_type,
1978- std::string *charset ) {
1979- std::string::size_type pos = s.find( ';' );
1980- *mime_type = s.substr( 0, pos );
1981-
1982- if ( std::strncmp( mime_type->c_str(), "text/", 5 ) == 0 ) {
1983- //
1984- // RFC 2616: "Hypertext Transfer Protocol -- HTTP/1.1," section 3.7.1,
1985- // "Canonicalization and Text Defaults":
1986- //
1987- // The "charset" parameter is used with some media types to define the
1988- // character set (section 3.4) of the data. When no explicit charset
1989- // parameter is provided by the sender, media subtypes of the "text"
1990- // type are defined to have a default charset value of "ISO-8859-1" when
1991- // received via HTTP.
1992- //
1993- *charset = "ISO-8859-1";
1994- } else
1995- charset->clear();
1996-
1997- if ( pos != std::string::npos ) {
1998- //
1999- // Parse: charset="?XXXXX"?[ (comment)]
2000- //
2001- if ( (pos = s.find( '=' )) != std::string::npos ) {
2002- std::string t = s.substr( pos + 1 );
2003- if ( !t.empty() ) {
2004- if ( t[0] == '"' ) {
2005- t.erase( 0, 1 );
2006- if ( (pos = t.find( '"' )) != std::string::npos )
2007- t.erase( pos );
2008- } else {
2009- if ( (pos = t.find( ' ' )) != std::string::npos )
2010- t.erase( pos );
2011- }
2012- *charset = t;
2013- }
2014- }
2015- }
2016-}
2017-
2018-namespace http_client {
2019-
2020- HttpResponseParser::HttpResponseParser(RequestHandler& aHandler, CURL* aCurl,
2021- ErrorThrower& aErrorThrower,
2022- std::string aOverridenContentType,
2023- bool aStatusOnly) :
2024- theHandler(aHandler),
2025- theCurl(aCurl),
2026- theErrorThrower(aErrorThrower),
2027- theStatus(-1),
2028- theStreamBuffer(0),
2029- theInsideRead(false),
2030- theOverridenContentType(aOverridenContentType),
2031- theStatusOnly(aStatusOnly),
2032- theSelfContained(true)
2033- {
2034- registerHandler();
2035- theStreamBuffer = new zorba::curl::streambuf(theCurl);
2036- }
2037-
2038- HttpResponseParser::~HttpResponseParser()
2039- {
2040- delete theStreamBuffer;
2041- }
2042-
2043- int HttpResponseParser::parse()
2044- {
2045- theStreamBuffer->setInformer(this);
2046- theHandler.begin();
2047- int lCode = 0;
2048- lCode = theStreamBuffer->multi_perform();
2049- if (lCode)
2050- return lCode;
2051- if (!theStatusOnly) {
2052-
2053- if (!theOverridenContentType.empty()) {
2054- parse_content_type(
2055- theOverridenContentType, &theCurrentContentType, &theCurrentCharset
2056- );
2057- }
2058-
2059- std::auto_ptr<std::istream> lStream;
2060- try {
2061- if ( !theCurrentCharset.empty() &&
2062- transcode::is_necessary( theCurrentCharset.c_str() ) ) {
2063- lStream.reset(
2064- new transcode::stream<std::istream>(
2065- theCurrentCharset.c_str(), theStreamBuffer
2066- )
2067- );
2068- } else
2069- lStream.reset(new std::istream(theStreamBuffer));
2070- }
2071- catch ( std::invalid_argument const &e ) {
2072- theErrorThrower.raiseException(
2073- "http://zorba.io/modules/zorba-errors", "ZXQP0006", e.what()
2074- );
2075- }
2076-
2077- Item lItem;
2078- if (theCurrentContentType == "text/xml" ||
2079- theCurrentContentType == "application/xml" ||
2080- theCurrentContentType == "text/xml-external-parsed-entity" ||
2081- theCurrentContentType == "application/xml-external-parsed-entity" ||
2082- theCurrentContentType.find("+xml") == theCurrentContentType.size()-4) {
2083- lItem = createXmlItem(*lStream.get());
2084- } else if (theCurrentContentType.find("text/") == 0) {
2085- lItem = createTextItem(lStream.release());
2086- } else {
2087- lItem = createBase64Item(*lStream.get());
2088- }
2089- if (!lItem.isNull()) {
2090- theHandler.any(lItem);
2091- }
2092- if (!theInsideRead) {
2093- theHandler.beginResponse(theStatus, theMessage);
2094- } else {
2095- theHandler.endBody();
2096- }
2097- }
2098- if (!theInsideRead) {
2099- theHandler.beginResponse(theStatus, theMessage);
2100- for (std::vector<std::pair<std::string, std::string> >::iterator i = theHeaders.begin();
2101- i != theHeaders.end(); ++i) {
2102- theHandler.header(i->first, i->second);
2103- }
2104- }
2105- theHandler.endResponse();
2106- theHandler.end();
2107- return lCode;
2108- }
2109-
2110- void HttpResponseParser::beforeRead()
2111- {
2112- if (theInsideRead) {
2113- return;
2114- }
2115- theInsideRead = true;
2116- theHandler.beginResponse(theStatus, theMessage);
2117- for ( headers_type::const_iterator
2118- lIter = theHeaders.begin(); lIter != theHeaders.end(); ++lIter) {
2119- theHandler.header(lIter->first, lIter->second);
2120- }
2121- if (!theStatusOnly)
2122- theHandler.beginBody(theCurrentContentType, "", NULL);
2123- }
2124-
2125- void HttpResponseParser::afterRead()
2126- {
2127- }
2128-
2129- void HttpResponseParser::registerHandler()
2130- {
2131- curl_easy_setopt(theCurl, CURLOPT_HEADERFUNCTION, &curl_headerfunction);
2132- curl_easy_setopt(theCurl, CURLOPT_HEADERDATA, this);
2133- }
2134-
2135- size_t HttpResponseParser::curl_headerfunction( void *ptr, size_t size,
2136- size_t nmemb, void *data )
2137- {
2138- size_t lSize = size*nmemb;
2139- size_t lResult = lSize;
2140- HttpResponseParser* lParser = static_cast<HttpResponseParser*>(data);
2141- if (lParser->theInsideRead) {
2142- lParser->theHandler.endBody();
2143- lParser->theInsideRead = false;
2144- }
2145- const char* lDataChar = (const char*) ptr;
2146- while (lSize != 0 && (lDataChar[lSize - 1] == 10
2147- || lDataChar[lSize - 1] == 13)) {
2148- lSize--;
2149- }
2150- if (lSize == 0) {
2151- return lResult;
2152- }
2153- std::string lData(lDataChar, lSize);
2154-
2155- if (lData.find("HTTP") == 0) {
2156- lParser->parseStatusAndMessage(lData);
2157- return lResult;
2158- }
2159- std::string::size_type lPos = lData.find(':');
2160- if (lPos == std::string::npos) {
2161- return lResult;
2162- }
2163- std::string lName = lData.substr(0, lPos);
2164- std::string lValue = lData.substr(lPos + 2);
2165- {
2166- std::string::size_type lPosition = lValue.size() - 1;
2167- while (true) {
2168- if (lPosition != std::string::npos) {
2169- break;
2170- }
2171- if (lValue[lPosition] == '\n' || lValue[lPosition] == '\r') {
2172- --lPosition;
2173- } else {
2174- break;
2175- }
2176- }
2177- lValue = lValue.substr(0, lPosition + 1);
2178- }
2179- String lNameS = fn::lower_case( lName );
2180- if (lNameS == "content-type") {
2181- parse_content_type(
2182- lValue, &lParser->theCurrentContentType, &lParser->theCurrentCharset
2183- );
2184- } else if (lNameS == "content-id") {
2185- lParser->theId = lValue;
2186- } else if (lNameS == "content-description") {
2187- lParser->theDescription = lValue;
2188- }
2189- lParser->theHeaders.push_back(
2190- std::pair<std::string, std::string>(lName, lValue));
2191- return lResult;
2192- }
2193-
2194- void HttpResponseParser::parseStatusAndMessage(std::string const &aHeader)
2195- {
2196- std::string::size_type lPos = aHeader.find(' ');
2197- assert(lPos != std::string::npos);
2198- std::string lStatus = aHeader.substr(lPos, aHeader.find(' ', lPos + 1));
2199- theMessage = aHeader.substr(aHeader.find(' ', lPos + 1) + 1);
2200- {
2201- std::string::size_type lPosition = theMessage.size() - 1;
2202- while (true) {
2203- if (lPosition != std::string::npos) {
2204- break;
2205- }
2206- if (theMessage[lPosition] == '\n' || theMessage[lPosition] == '\r') {
2207- --lPosition;
2208- } else {
2209- break;
2210- }
2211- }
2212- theMessage = theMessage.substr(0, lPosition + 1);
2213- }
2214- std::stringstream lStream(lStatus);
2215- lStream >> theStatus;
2216- // everything that is not a valid http status is an error
2217- if (theStatus < 100) {
2218- theErrorThrower.raiseException("http://expath.org/ns/error", "HC001", "An HTTP error occurred");
2219- }
2220- }
2221-
2222- static void streamReleaser(std::istream* aStream)
2223- {
2224- if (!aStream)
2225- return;
2226-
2227- // This istream contains our curl stream buffer, so we have to delete it too
2228- std::streambuf *const sbuf = aStream->rdbuf();
2229- if ( transcode::streambuf *tbuf =
2230- dynamic_cast<transcode::streambuf*>( sbuf ) )
2231- delete tbuf->orig_streambuf();
2232- else
2233- delete sbuf;
2234- delete aStream;
2235- }
2236-
2237- zorba::Item HttpResponseParser::createTextItem(std::istream* aStream)
2238- {
2239- ItemFactory* lFactory = Zorba::getInstance(0)->getItemFactory();
2240-
2241- // When we create a StreamableString, memory ownership gets very convoluted
2242- // because the StreamableString object has a longer lifecycle than the
2243- // iterator which creates it. The StreamableString object depends on its
2244- // istream, which in turn depends on its read buffer. For us, the read
2245- // buffer in turn depends on the HttpResponseParser (this object) because
2246- // it is registered as the "informer" (callback object) for
2247- // theStreamBuffer. Therefore, this HttpResponseParser object is no longer
2248- // "self-contained". We delegate ownership of ourself to theStreamBuffer
2249- // and mark ourselves as no longer being self-contained.
2250- theStreamBuffer->setOwnInformer(true);
2251- theSelfContained = false;
2252-
2253- // The ownership of theStreamBuffer, in turn, is delegated to the
2254- // StreamableString object (via streamReleaser, which will free the
2255- // istream's rdbuf).
2256- theStreamBuffer = NULL;
2257- return lFactory->createStreamableString(*aStream, &streamReleaser, false);
2258- }
2259-
2260- zorba::Item HttpResponseParser::createBase64Item( std::istream& aStream )
2261- {
2262- ItemFactory* lFactory = Zorba::getInstance(0)->getItemFactory();
2263- // TODO: once a proper streaming implementation is in place this can be
2264- // changed. This required a Base64 encoding stream since the item factory
2265- // work only builds base64binary and assumes the data is already encoded.
2266- String lEncoded = base64::encode(aStream);
2267- return lFactory->createBase64Binary(lEncoded.data(), lEncoded.size(), true);
2268- }
2269-
2270- zorba::Item HttpResponseParser::createXmlItem( std::istream& aStream )
2271- {
2272- try {
2273- XmlDataManager* lDM = Zorba::getInstance(0)->getXmlDataManager();
2274- return lDM->parseXML(aStream);
2275- } catch (...) {
2276- theErrorThrower.raiseException("http://expath.org/ns/error",
2277- "HC002", "Error parsing the entity content as XML.");
2278- //compiler does not recognize, that this function throws an exception, so we just
2279- // return something
2280- return Item();
2281- }
2282- }
2283-
2284-} // namespace http_client
2285-} // namespace zorba
2286-/* vim:set et sw=2 ts=2: */
2287
2288=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_parser.h'
2289--- modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_parser.h 2013-02-07 17:24:36 +0000
2290+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/http_response_parser.h 1970-01-01 00:00:00 +0000
2291@@ -1,92 +0,0 @@
2292-/*
2293- * Copyright 2006-2008 The FLWOR Foundation.
2294- *
2295- * Licensed under the Apache License, Version 2.0 (the "License");
2296- * you may not use this file except in compliance with the License.
2297- * You may obtain a copy of the License at
2298- *
2299- * http://www.apache.org/licenses/LICENSE-2.0
2300- *
2301- * Unless required by applicable law or agreed to in writing, software
2302- * distributed under the License is distributed on an "AS IS" BASIS,
2303- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2304- * See the License for the specific language governing permissions and
2305- * limitations under the License.
2306- */
2307-#ifndef HTTP_RESPONSE_PARSER_H
2308-#define HTTP_RESPONSE_PARSER_H
2309-#include <vector>
2310-#include <string>
2311-#include <map>
2312-
2313-#include <curl/curl.h>
2314-
2315-#include "inform_data_read.h"
2316-#include "error_thrower.h"
2317-#include "http_response_handler.h"
2318-
2319-namespace zorba {
2320-class Item;
2321-
2322-namespace curl {
2323- class streambuf;
2324-}
2325-
2326-namespace http_client {
2327- class RequestHandler;
2328-
2329- class HttpResponseParser : public InformDataRead {
2330- private:
2331- RequestHandler& theHandler;
2332- CURL* theCurl;
2333- ErrorThrower& theErrorThrower;
2334- std::string theCurrentContentType;
2335- std::string theCurrentCharset;
2336- typedef std::vector<std::pair<std::string, std::string> > headers_type;
2337- headers_type theHeaders;
2338- int theStatus;
2339- std::string theMessage;
2340- zorba::curl::streambuf* theStreamBuffer;
2341- std::string theId;
2342- std::string theDescription;
2343- bool theInsideRead;
2344- std::map<std::string, std::string> theCodeMap;
2345- std::string theOverridenContentType;
2346- bool theStatusOnly;
2347- bool theSelfContained;
2348- public:
2349- HttpResponseParser(
2350- RequestHandler& aHandler,
2351- CURL* aCurl,
2352- ErrorThrower& aErrorThrower,
2353- std::string aOverridenContentType = "",
2354- bool aStatusOnly = false);
2355- virtual ~HttpResponseParser();
2356- int parse();
2357- /**
2358- * After calling parse(), it is possible that HttpResponseParser will have
2359- * created some long-lived objects that depend on it. In that case, it will
2360- * also have arranged for itself to be de-allocated at some future time
2361- * when it is appropriate to do so. Therefore, in this case, the code which
2362- * created the HttpResponseParser should NOT free it. HttpResponseParser
2363- * refers to itself as "not self-contained" in this case, and this method
2364- * will return false.
2365- */
2366- bool selfContained() { return theSelfContained; }
2367- virtual void beforeRead();
2368- virtual void afterRead();
2369- private:
2370- void registerHandler();
2371- void parseStatusAndMessage(std::string const &aHeader);
2372- Item createXmlItem(std::istream& aStream);
2373- Item createHtmlItem(std::istream& aStream);
2374- Item createTextItem(std::istream* aStream);
2375- Item createBase64Item(std::istream& aStream);
2376-
2377- static size_t curl_headerfunction( void*, size_t, size_t, void* );
2378- };
2379-
2380-} // namespace http_client
2381-} // namespace zorba
2382-
2383-#endif //HTTP_RESPONSE_PARSER_H
2384
2385=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/inform_data_read.cpp'
2386--- modules/com/zorba-xquery/www/modules/http-client.xq.src/inform_data_read.cpp 2013-02-07 17:24:36 +0000
2387+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/inform_data_read.cpp 1970-01-01 00:00:00 +0000
2388@@ -1,22 +0,0 @@
2389-/*
2390- * Copyright 2006-2008 The FLWOR Foundation.
2391- *
2392- * Licensed under the Apache License, Version 2.0 (the "License");
2393- * you may not use this file except in compliance with the License.
2394- * You may obtain a copy of the License at
2395- *
2396- * http://www.apache.org/licenses/LICENSE-2.0
2397- *
2398- * Unless required by applicable law or agreed to in writing, software
2399- * distributed under the License is distributed on an "AS IS" BASIS,
2400- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2401- * See the License for the specific language governing permissions and
2402- * limitations under the License.
2403- */
2404-#include "inform_data_read.h"
2405-
2406-namespace zorba { namespace http_client {
2407- InformDataRead::~InformDataRead()
2408- {
2409- }
2410-}} //namespace zorba, http_client
2411
2412=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/inform_data_read.h'
2413--- modules/com/zorba-xquery/www/modules/http-client.xq.src/inform_data_read.h 2013-02-07 17:24:36 +0000
2414+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/inform_data_read.h 1970-01-01 00:00:00 +0000
2415@@ -1,27 +0,0 @@
2416-/*
2417- * Copyright 2006-2008 The FLWOR Foundation.
2418- *
2419- * Licensed under the Apache License, Version 2.0 (the "License");
2420- * you may not use this file except in compliance with the License.
2421- * You may obtain a copy of the License at
2422- *
2423- * http://www.apache.org/licenses/LICENSE-2.0
2424- *
2425- * Unless required by applicable law or agreed to in writing, software
2426- * distributed under the License is distributed on an "AS IS" BASIS,
2427- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2428- * See the License for the specific language governing permissions and
2429- * limitations under the License.
2430- */
2431-#ifndef INFORM_DATA_READ_H
2432-#define INFORM_DATA_READ_H
2433-namespace zorba { namespace http_client {
2434- class InformDataRead {
2435- public:
2436- virtual ~InformDataRead();
2437- public:
2438- virtual void beforeRead() = 0;
2439- virtual void afterRead() = 0;
2440- };
2441-}} //namespace zorba, http_client
2442-#endif //INFORM_DATA_READ_H
2443
2444=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/request_handler.cpp'
2445--- modules/com/zorba-xquery/www/modules/http-client.xq.src/request_handler.cpp 2013-02-07 17:24:36 +0000
2446+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/request_handler.cpp 1970-01-01 00:00:00 +0000
2447@@ -1,22 +0,0 @@
2448-/*
2449- * Copyright 2006-2008 The FLWOR Foundation.
2450- *
2451- * Licensed under the Apache License, Version 2.0 (the "License");
2452- * you may not use this file except in compliance with the License.
2453- * You may obtain a copy of the License at
2454- *
2455- * http://www.apache.org/licenses/LICENSE-2.0
2456- *
2457- * Unless required by applicable law or agreed to in writing, software
2458- * distributed under the License is distributed on an "AS IS" BASIS,
2459- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2460- * See the License for the specific language governing permissions and
2461- * limitations under the License.
2462- */
2463-#include "request_handler.h"
2464-
2465-namespace zorba { namespace http_client {
2466- RequestHandler::~RequestHandler()
2467- {
2468- }
2469-}} //namespace zorba, http_client
2470
2471=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/request_handler.h'
2472--- modules/com/zorba-xquery/www/modules/http-client.xq.src/request_handler.h 2013-02-07 17:24:36 +0000
2473+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/request_handler.h 1970-01-01 00:00:00 +0000
2474@@ -1,60 +0,0 @@
2475-/*
2476- * Copyright 2006-2008 The FLWOR Foundation.
2477- *
2478- * Licensed under the Apache License, Version 2.0 (the "License");
2479- * you may not use this file except in compliance with the License.
2480- * You may obtain a copy of the License at
2481- *
2482- * http://www.apache.org/licenses/LICENSE-2.0
2483- *
2484- * Unless required by applicable law or agreed to in writing, software
2485- * distributed under the License is distributed on an "AS IS" BASIS,
2486- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2487- * See the License for the specific language governing permissions and
2488- * limitations under the License.
2489- */
2490-#ifndef REQUEST_HANDLER_H
2491-#define REQUEST_HANDLER_H
2492-
2493-namespace zorba {
2494-class String;
2495-class Item;
2496-class ItemSequence;
2497-
2498-namespace http_client {
2499- class RequestHandler {
2500- public:
2501- virtual ~RequestHandler();
2502- public:
2503- virtual void begin() = 0;
2504- virtual void beginResponse(int aStatus, String aMessage) = 0;
2505- virtual void endResponse() = 0;
2506- virtual void beginRequest(
2507- String aMethod,
2508- String href,
2509- bool aStatusOnly,
2510- String aUsername,
2511- String aPassword,
2512- String aAuthMethod,
2513- bool aSendAuthorization,
2514- String aOverrideContentType,
2515- bool aFollowRedirect,
2516- int aTimeout = -1) = 0;
2517- virtual void endRequest() = 0;
2518- virtual void header(String aName, String aValue) = 0;
2519- virtual void beginBody(
2520- String aContentType,
2521- String aSrc,
2522- ItemSequence* aSerializerOptions) = 0;
2523- virtual void any(Item aItem) = 0;
2524- virtual void endBody() = 0;
2525- virtual void beginMultipart(String aContentType, String aBoundary) = 0;
2526- virtual void endMultipart() = 0;
2527- virtual void end() = 0;
2528- public: // status
2529- virtual bool isHeadRequest() const = 0;
2530- };
2531-}
2532-}
2533-
2534-#endif //REQUEST_HANDLER_H
2535
2536=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/request_parser.cpp'
2537--- modules/com/zorba-xquery/www/modules/http-client.xq.src/request_parser.cpp 2013-02-07 17:24:36 +0000
2538+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/request_parser.cpp 1970-01-01 00:00:00 +0000
2539@@ -1,276 +0,0 @@
2540-/*
2541- * Copyright 2006-2008 The FLWOR Foundation.
2542- *
2543- * Licensed under the Apache License, Version 2.0 (the "License");
2544- * you may not use this file except in compliance with the License.
2545- * You may obtain a copy of the License at
2546- *
2547- * http://www.apache.org/licenses/LICENSE-2.0
2548- *
2549- * Unless required by applicable law or agreed to in writing, software
2550- * distributed under the License is distributed on an "AS IS" BASIS,
2551- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2552- * See the License for the specific language governing permissions and
2553- * limitations under the License.
2554- */
2555-#include "request_parser.h"
2556-#include "request_handler.h"
2557-#include "error_thrower.h"
2558-
2559-#include <cassert>
2560-#include <iostream>
2561-
2562-#include <zorba/zorba.h>
2563-#include <zorba/api_shared_types.h>
2564-#include <zorba/item.h>
2565-#include <zorba/zorba_string.h>
2566-#include <zorba/iterator.h>
2567-#include <zorba/store_consts.h>
2568-#include <zorba/vector_item_sequence.h>
2569-#include <zorba/xquery_functions.h>
2570-
2571-namespace zorba { namespace http_client {
2572- /*class AttributesSequence : public ItemSequence {
2573- std::vector<Item>& theItems;
2574- unsigned thePosition;
2575- unsigned theSize;
2576- public:
2577- AttributesSequence(std::vector<Item>& aItems)
2578- : theItems(aItems), thePosition(0), theSize((unsigned)aItems.size()) {}
2579- virtual bool next(Item& aItem)
2580- {
2581- if (thePosition < theSize) {
2582- aItem = theItems[thePosition++];
2583- return true;
2584- }
2585- return false;
2586- }
2587- virtual bool
2588- nextSerializableItem(Item& item) { return next(item); }
2589- };
2590- */
2591- bool RequestParser::parse(const Item& aItem)
2592- {
2593- theHandler->begin();
2594- bool lResult = parseItem(aItem);
2595- theHandler->end();
2596- return lResult;
2597- }
2598-
2599- bool RequestParser::parseItem(const Item& aItem)
2600- {
2601- if (aItem.getNodeKind() == store::StoreConsts::commentNode)
2602- return true;
2603- Item lQName;
2604- aItem.getNodeName(lQName);
2605- String lLocalName = lQName.getLocalName();
2606- if (lLocalName == "request") {
2607- if (!handleRequest(aItem)) return false;
2608- } else if (lLocalName == "response") {
2609- if (!handleResponse(aItem)) return false;
2610- } else if (lLocalName == "header") {
2611- if (!handleHeader(aItem)) return false;
2612- } else if (lLocalName == "multipart") {
2613- if (!handleMultipart(aItem)) return false;
2614- } else if (lLocalName == "body") {
2615- if (!handleBody(aItem)) return false;
2616- }
2617- return true;
2618- }
2619-
2620- bool RequestParser::handleRequest( const Item& aItem )
2621- {
2622- String lMethod;
2623- String lHref;
2624- bool lStatusOnly = false;
2625- String lUsername;
2626- String lPassword;
2627- String lAuthMethod;
2628- bool lSendAuthorization = false;
2629- String lOverrideContentType;
2630- bool lFollowRedirect = false;
2631- bool lUserDefinedFollowRedirect = false;
2632- int lTimeout = -1;
2633-
2634- Iterator_t lIter = aItem.getAttributes();
2635- lIter->open();
2636- Item lItem;
2637- while (lIter->next(lItem)) {
2638- Item lQName;
2639- lItem.getNodeName(lQName);
2640- String lLocalName = lQName.getLocalName();
2641- std::string lLocalNameString = lLocalName.c_str();
2642- if (lLocalName == "method") {
2643- lMethod = lItem.getStringValue();
2644- } else if (lLocalName == "href") {
2645- lHref = lItem.getStringValue();
2646- } else if (lLocalName == "status-only") {
2647- lStatusOnly = lItem.getStringValue() == "true";
2648- } else if (lLocalName == "username") {
2649- lUsername = lItem.getStringValue();
2650- } else if (lLocalName == "password") {
2651- lPassword = lItem.getStringValue();
2652- } else if (lLocalName == "auth-method") {
2653- lAuthMethod = lItem.getStringValue();
2654- } else if (lLocalName == "send-authorization") {
2655- String lString = lItem.getStringValue();
2656- lSendAuthorization = lString == "true";
2657- } else if (lLocalName == "override-media-type") {
2658- lOverrideContentType = lItem.getStringValue();
2659- } else if (lLocalName == "follow-redirect") {
2660- String lString = lItem.getStringValue();
2661- lFollowRedirect = lString == "true";
2662- lUserDefinedFollowRedirect = true;
2663- } else if (lLocalName == "timeout") {
2664- lTimeout = lItem.getIntValue();
2665- }
2666- }
2667-
2668- lMethod = fn::upper_case(lMethod);
2669-
2670- // follow-redirect: take care of the default (if the user didn't provide one)
2671- if (lMethod == "GET" || lMethod == "HEAD" || lMethod == "OPTIONS")
2672- {
2673- if (!lUserDefinedFollowRedirect)
2674- lFollowRedirect = "true";
2675- }
2676- else
2677- {
2678- if (lFollowRedirect)
2679- {
2680- std::ostringstream lMsg;
2681- lMsg << lMethod << ": cannot follow redirect";
2682- theThrower->raiseException(
2683- "http://expath.org/ns/error", "HCV02", lMsg.str()
2684- );
2685- }
2686- }
2687-
2688-
2689- theHandler->beginRequest(lMethod, lHref, lStatusOnly, lUsername,
2690- lPassword, lAuthMethod, lSendAuthorization, lOverrideContentType,
2691- lFollowRedirect, lTimeout);
2692- lIter = aItem.getChildren();
2693- lIter->open();
2694- while (lIter->next(lItem)) {
2695- if (!parseItem(lItem)) {
2696- return false;
2697- }
2698- }
2699- theHandler->endRequest();
2700- return true;
2701- }
2702-
2703- bool RequestParser::handleResponse( const Item aItem )
2704- {
2705- int lStatus = 0;
2706- String lMessage;
2707-
2708- Iterator_t lIter = aItem.getAttributes();
2709- lIter->open();
2710- Item lItem;
2711- while (lIter->next(lItem)) {
2712- Item lQName;
2713- lItem.getNodeName(lQName);
2714- String lLocalName = lQName.getLocalName();
2715- if (lLocalName == "status") {
2716- lStatus = lItem.getIntValue();
2717- } else if (lLocalName == "message") {
2718- lMessage = lItem.getStringValue();
2719- }
2720- }
2721-
2722- theHandler->beginResponse(lStatus, lMessage);
2723- lIter = aItem.getChildren();
2724- lIter->open();
2725- while (lIter->next(lItem)) {
2726- if (!parseItem(lItem)) return false;
2727- }
2728- theHandler->endResponse();
2729- return true;
2730- }
2731-
2732- bool RequestParser::handleHeader( const Item& aItem )
2733- {
2734- String lName;
2735- String lValue;
2736- Iterator_t lIter = aItem.getAttributes();
2737- lIter->open();
2738- Item lItem;
2739- while (lIter->next(lItem)) {
2740- Item lQName;
2741- lItem.getNodeName(lQName);
2742- String lLocalName = lQName.getLocalName();
2743- if (lLocalName == "name") {
2744- lName = lItem.getStringValue();
2745- } else if (lLocalName == "value") {
2746- lValue = lItem.getStringValue();
2747- }
2748- }
2749- theHandler->header(lName, lValue);
2750- return true;
2751- }
2752-
2753- bool RequestParser::handleBody( const Item& aItem )
2754- {
2755- String lContentType;
2756- String lEncoding;
2757- String lId;
2758- String lDescription;
2759- String lSrc;
2760-
2761- Iterator_t lIter = aItem.getAttributes();
2762- lIter->open();
2763- Item lItem;
2764- std::vector<Item> lItems;
2765- while (lIter->next(lItem)) {
2766- Item lQName;
2767- lItem.getNodeName(lQName);
2768- String lLocalName = lQName.getLocalName();
2769- if (lLocalName == "media-type") {
2770- lContentType = lItem.getStringValue();
2771- } else if (lLocalName == "src") {
2772- lSrc = lItem.getStringValue();
2773- } else {
2774- lItems.push_back(lItem);
2775- }
2776- }
2777- std::auto_ptr<VectorItemSequence> lSequence(new VectorItemSequence(lItems));
2778- theHandler->beginBody(lContentType, lSrc, lSequence.get());
2779- lIter = aItem.getChildren();
2780- lIter->open();
2781- while (lIter->next(lItem)) {
2782- theHandler->any(lItem);
2783- }
2784- theHandler->endBody();
2785- return true;
2786- }
2787-
2788- bool RequestParser::handleMultipart( const Item& aItem )
2789- {
2790- String lContentType;
2791- String lBoundary;
2792-
2793- Iterator_t lIter = aItem.getAttributes();
2794- lIter->open();
2795- Item lItem;
2796- while (lIter->next(lItem)) {
2797- Item lQName;
2798- lItem.getNodeName(lQName);
2799- String lLocalName = lQName.getLocalName();
2800- if (lLocalName == "media-type") {
2801- lContentType = lItem.getStringValue();
2802- } else if (lLocalName == "boundary") {
2803- lBoundary = lItem.getStringValue();
2804- }
2805- }
2806- theHandler->beginMultipart(lContentType, lBoundary);
2807- lIter = aItem.getChildren();
2808- lIter->open();
2809- while (lIter->next(lItem)) {
2810- if (!parseItem(lItem)) return false;
2811- }
2812- theHandler->endMultipart();
2813- return true;
2814- }
2815-}}
2816
2817=== removed file 'modules/com/zorba-xquery/www/modules/http-client.xq.src/request_parser.h'
2818--- modules/com/zorba-xquery/www/modules/http-client.xq.src/request_parser.h 2013-02-07 17:24:36 +0000
2819+++ modules/com/zorba-xquery/www/modules/http-client.xq.src/request_parser.h 1970-01-01 00:00:00 +0000
2820@@ -1,46 +0,0 @@
2821-/*
2822- * Copyright 2006-2008 The FLWOR Foundation.
2823- *
2824- * Licensed under the Apache License, Version 2.0 (the "License");
2825- * you may not use this file except in compliance with the License.
2826- * You may obtain a copy of the License at
2827- *
2828- * http://www.apache.org/licenses/LICENSE-2.0
2829- *
2830- * Unless required by applicable law or agreed to in writing, software
2831- * distributed under the License is distributed on an "AS IS" BASIS,
2832- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2833- * See the License for the specific language governing permissions and
2834- * limitations under the License.
2835- */
2836-#ifndef REQUEST_PARSER_H
2837-#define REQUEST_PARSER_H
2838-
2839-namespace zorba {
2840-class Item;
2841-
2842-namespace http_client {
2843-class RequestHandler;
2844-class ErrorThrower;
2845-
2846-class RequestParser {
2847-protected:
2848- RequestHandler* theHandler;
2849- ErrorThrower* theThrower;
2850-
2851-public:
2852- RequestParser(RequestHandler* aHandler, ErrorThrower& aThrower) : theHandler(aHandler), theThrower(&aThrower) {}
2853- bool parse(const Item& aItem);
2854-
2855-private:
2856- bool parseItem(const Item& aItem);
2857- bool handleRequest(const Item& aItem);
2858- bool handleResponse(const Item aItem);
2859- bool handleHeader(const Item& aItem);
2860- bool handleBody(const Item& aItem);
2861- bool handleMultipart(const Item& aItem);
2862-};
2863-} //namespace zorba
2864-} //namespace http_request
2865-
2866-#endif // REQUEST_PARSER_H
2867
2868=== added directory 'modules/http-client'
2869=== added file 'modules/http-client/CMakeLists.txt'
2870--- modules/http-client/CMakeLists.txt 1970-01-01 00:00:00 +0000
2871+++ modules/http-client/CMakeLists.txt 2013-07-25 09:33:27 +0000
2872@@ -0,0 +1,60 @@
2873+# Copyright 2006-2012 The FLWOR Foundation.
2874+#
2875+# Licensed under the Apache License, Version 2.0 (the "License");
2876+# you may not use this file except in compliance with the License.
2877+# You may obtain a copy of the License at
2878+#
2879+# http://www.apache.org/licenses/LICENSE-2.0
2880+#
2881+# Unless required by applicable law or agreed to in writing, software
2882+# distributed under the License is distributed on an "AS IS" BASIS,
2883+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2884+# See the License for the specific language governing permissions and
2885+# limitations under the License.
2886+
2887+#
2888+# cURL
2889+#
2890+SET (CURL_FOUND)
2891+IF(ZORBA_SUPPRESS_CURL)
2892+ MESSAGE(STATUS "ZORBA_SUPPRESS_CURL is true - not searching for cURL library")
2893+ELSE(ZORBA_SUPPRESS_CURL)
2894+ MESSAGE(STATUS "Looking for cURL")
2895+ FIND_PACKAGE(CURL)
2896+
2897+ IF(CURL_FOUND)
2898+ MESSAGE(STATUS "Found cURL library -- " ${CURL_LIBRARIES})
2899+ INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
2900+
2901+ DECLARE_ZORBA_MODULE(FILE xml/http-client-error.xq
2902+ URI "http://expath.org/ns/error")
2903+
2904+ DECLARE_ZORBA_SCHEMA(FILE xml/http-client.xsd
2905+ URI "http://expath.org/ns/http-client")
2906+
2907+ DECLARE_ZORBA_MODULE(FILE xml/http-client.xq VERSION 2.0
2908+ URI "http://www.zorba-xquery.com/modules/http-client"
2909+ LINK_LIBRARIES ${CURL_LIBRARIES})
2910+
2911+ DECLARE_ZORBA_MODULE(FILE json/http-client.xq VERSION 1.0
2912+ URI "http://zorba.io/modules/http-client"
2913+ LINK_LIBRARIES ${CURL_LIBRARIES})
2914+
2915+ IF (WIN32) # Copy certificates for windows only
2916+ IF (MSVC_IDE)
2917+ SET(CACERT_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../../bin/${CMAKE_BUILD_TYPE}/cacert.pem")
2918+ ELSE (MSVC_IDE)
2919+ SET(CACERT_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../../bin/cacert.pem")
2920+ ENDIF (MSVC_IDE)
2921+ CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cacert.pem" ${CACERT_DESTINATION} COPYONLY)
2922+ INSTALL(FILES ${CACERT_DESTINATION} DESTINATION bin)
2923+ ENDIF (WIN32)
2924+
2925+ ELSE(CURL_FOUND)
2926+ MESSAGE(STATUS "The cURL library was not found - http-client will not be built")
2927+ ENDIF(CURL_FOUND)
2928+ENDIF(ZORBA_SUPPRESS_CURL)
2929+SET(ZORBA_HAVE_CURL ${CURL_FOUND} CACHE BOOL "Whether Zorba found cURL" FORCE)
2930+MARK_AS_ADVANCED(ZORBA_HAVE_CURL)
2931+
2932+# vim:set et sw=2 ts=2:
2933
2934=== added directory 'modules/http-client/json'
2935=== added file 'modules/http-client/json/http-client.jsd'
2936--- modules/http-client/json/http-client.jsd 1970-01-01 00:00:00 +0000
2937+++ modules/http-client/json/http-client.jsd 2013-07-25 09:33:27 +0000
2938@@ -0,0 +1,215 @@
2939+{
2940+ "$namespace": "http://zorba.io/modules/http-client",
2941+ "$about": "This JSound schema defines the types of requests and
2942+ responses used in the http://28.io/http-client module",
2943+ "$types": [
2944+ {
2945+ "$kind": "object",
2946+ "$name": "headers",
2947+ "$about": "This type represents a set of headers. Each header is represented
2948+ by a different name-value pair.",
2949+ "$constraints" : "every $key in keys($$) satisfies $$.$key instance of string"
2950+
2951+ },
2952+ {
2953+ "$kind": "object",
2954+ "$name": "body",
2955+ "$about": "This type represents the body of an HTTP request or an HTTP
2956+ response. In multi-part requests and responses, it represents the
2957+ body of a single part.",
2958+ "$content": {
2959+ "media-type": {
2960+ "$type": "string",
2961+ "$about": "This field is the media type of the body."
2962+ },
2963+ "src": {
2964+ "$type": "anyURI",
2965+ "$about": "This field, used only in HTTP requests, is used to specify the URL at
2966+ which the request can be found. It is mutually exclusive with the content
2967+ field.",
2968+ "$optional": true
2969+ },
2970+ "content": {
2971+ "$type": "string",
2972+ "$about": "The HTTP request or response body. It is mutually exclusive with the src
2973+ field.",
2974+ "$optional": true
2975+ }
2976+ },
2977+ "$constraints" : "count($$.src) + count($$.content) le 1"
2978+ },
2979+ {
2980+ "$kind": "object",
2981+ "$name": "part",
2982+ "$about": "This type represents each single part of a multipart HTTP request or
2983+ response.",
2984+ "$content": {
2985+ "headers": {
2986+ "$type": "headers",
2987+ "$optional": true,
2988+ "$about": "This field specifies the part headers."
2989+ },
2990+ "body": {"$type": "body"}
2991+ }
2992+ },
2993+ {
2994+ "$kind": "object",
2995+ "$name": "multipart",
2996+ "$about": "This type represents a multipart HTTP request or response.",
2997+ "$content": {
2998+ "media-type": {
2999+ "$type": "string"
3000+ "$about": "The media-type attribute is the media type of the request or
3001+ response, and has to be a multipart media type (that is, its
3002+ main type must be multipart)."
3003+ },
3004+ "boundary": {
3005+ "$type": "string",
3006+ "$optional": true,
3007+ "$about": "The boundary attribute is the boundary marker used to separate
3008+ the several parts in the message (the value of the attribute is
3009+ prefixed with "--" to form the actual boundary marker in the
3010+ request; on the other way, this prefix is removed from the boundary
3011+ marker in the response to set the value of the attribute."
3012+ },
3013+ "parts": {
3014+ "$kind": "array",
3015+ "$content": ["part"],
3016+ "$about": "The parts of the multipart request.",
3017+ "$optional": true
3018+ }
3019+ }
3020+ },
3021+ {
3022+ "$kind": "object",
3023+ "$name": "options",
3024+ "$about": "This type represents an HTTP request options.",
3025+ "$content": {
3026+ "status-only": {
3027+ "$type": "boolean",
3028+ "$optional": true,
3029+ "$about": "Controls how the response will look like; if true, only the status code
3030+ and the headers are returned, the content is not."
3031+ },
3032+ "override-media-type": {
3033+ "$type": "string",
3034+ "$about": "Is a MIME type that will override the Content-Type header returned
3035+ by the server.",
3036+ "$optional": true
3037+ },
3038+ "follow-redirect": {
3039+ "$type": "boolean",
3040+ "$optional": true,
3041+ "$about": "Control whether an http redirect is automatically followed or not. If
3042+ it is false, the http redirect is returned as the response. If it is
3043+ true (the default) the function tries to follow the redirect, by
3044+ sending the same request to the new address (including body, headers,
3045+ and authentication credentials.) Maximum one redirect is followed
3046+ (there is no attempt to follow a redirect in response to following a
3047+ first redirect.)"
3048+ },
3049+ "timeout": {
3050+ "$type": "integer",
3051+ "$optional": true,
3052+ "$about": "Is the maximum number of seconds to wait for the server to respond. If
3053+ this time duration is reached, an error is thrown."
3054+ },
3055+ "user-agent": {
3056+ "$type": "string",
3057+ "$optional": true,
3058+ "$about": "The user agent sent to the server when issuing the request."
3059+ },
3060+ }
3061+ },
3062+ {
3063+ "$kind": "object",
3064+ "$name": "authentication",
3065+ "$about": "This type represents an HTTP authentication.",
3066+ "$content": {
3067+ "username": {
3068+ "$type": "string",
3069+ "$about": "The authentication username."
3070+ },
3071+ "password": {
3072+ "$type": "string",
3073+ "$about": "The authentication password."
3074+ },
3075+ "auth-method": {
3076+ "$type": "string",
3077+ "$about": "The authentication method."
3078+ }
3079+ }
3080+ },
3081+ {
3082+ "$kind": "object",
3083+ "$name": "request",
3084+ "$content": {
3085+ "method": {
3086+ "$type": "string",
3087+ "$about: "Is the http verb to use, as GET, POST, etc. It is case insensitive."
3088+ },
3089+ "href": {
3090+ "$type": "anyURI",
3091+ "$about": "Is the URI the request has to be sent to. It can be overridden by the
3092+ parameter $href."
3093+ },
3094+ "authentication": {
3095+ "$type": "authentication",
3096+ "$optional": true,
3097+ "$about": "Specifies the HTTP authentication when sending the request."
3098+ },
3099+ "options": {
3100+ "$type": "options",
3101+ "$optional": true,
3102+ "$about": "Specifies the HTTP request options."
3103+ },
3104+ "headers": {
3105+ "$type": "headers",
3106+ "$optional": true,
3107+ "$about": "Specifies the HTTP request headers."
3108+ },
3109+ "body": {
3110+ "$type": "body",
3111+ "$optional": true,
3112+ "$about": "Specifies the body of a non-multipart HTTP request."
3113+ },
3114+ "multipart": {
3115+ "$type": "multipart",
3116+ "$optional": true,
3117+ "$about": "Specifies a multipart HTTP request."
3118+ }
3119+ },
3120+ "$constraints" : "count($$.body) + count($$.multipart) le 1"
3121+ },
3122+ {
3123+ "$kind": "object",
3124+ "$name": "response",
3125+ "$content": {
3126+ "status": {
3127+ "$type": "integer",
3128+ "$about": "This is the HTTP status code returned by the server."
3129+ },
3130+ "message": {
3131+ "$type": "string",
3132+ "$about": "This is the message returned by the server on the status line."
3133+ },
3134+ "headers": {
3135+ "$type": "headers",
3136+ "$optional": true,
3137+ "$about": "The reponse headers returned by the server."
3138+ },
3139+ "body": {
3140+ "$type": "body",
3141+ "$optional": true,
3142+ "$about": "The body of a non-multipart HTTP response."
3143+ },
3144+ "multipart": {
3145+ "$type": "multipart",
3146+ "$optional": true,
3147+ "$about": "Specifies a multipart HTTP response."
3148+ }
3149+ },
3150+ "$constraints" : "count($$.body) + count($$.multipart) le 1"
3151+ }
3152+ ]
3153+}
3154\ No newline at end of file
3155
3156=== added file 'modules/http-client/json/http-client.xq'
3157--- modules/http-client/json/http-client.xq 1970-01-01 00:00:00 +0000
3158+++ modules/http-client/json/http-client.xq 2013-07-25 09:33:27 +0000
3159@@ -0,0 +1,692 @@
3160+jsoniq version "1.0";
3161+
3162+(:
3163+ : Copyright 2006-2013 The FLWOR Foundation.
3164+ :
3165+ : Licensed under the Apache License, Version 2.0 (the "License");
3166+ : you may not use this file except in compliance with the License.
3167+ : You may obtain a copy of the License at
3168+ :
3169+ : http://www.apache.org/licenses/LICENSE-2.0
3170+ :
3171+ : Unless required by applicable law or agreed to in writing, software
3172+ : distributed under the License is distributed on an "AS IS" BASIS,
3173+ : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3174+ : See the License for the specific language governing permissions and
3175+ : limitations under the License.
3176+ :)
3177+
3178+
3179+(:~
3180+ : <p>
3181+ : This module provides functions for performing HTTP requests.
3182+ : </p>
3183+ :
3184+ : <h2>A simple GET request using the get#1 convenience function</h2>
3185+ :
3186+ : <pre>
3187+ : import module namespace http="http://zorba.io/modules/http-client";
3188+ : http:get("http://www.example.com")
3189+ : </pre>
3190+ :
3191+ : <p>
3192+ : This example makes a GET request to example.com and returns the server's response
3193+ : as a JSON object.
3194+ : </p>
3195+ :
3196+ : <pre>
3197+ : {
3198+ : "status" : 200,
3199+ : "message" : "OK",
3200+ : "headers" : {
3201+ : "Content-Length" : "1270",
3202+ : "Date" : "Tue, 11 Jun 2013 22:27:10 GMT",
3203+ : ...
3204+ : },
3205+ : "body" : {
3206+ : "media-type" : "text/html",
3207+ : "content" : "..."
3208+ : }
3209+ : }
3210+ : </pre>
3211+ :
3212+ : <h2 id="standard_return">Response format</h2>
3213+ :
3214+ : <p>Most functions in this module (all except <a href="#options-1">options#1</a>)
3215+ : return a single JSON item, describing the server's response, as in the previous
3216+ : example.
3217+ : The server status (integer) and message (string) fields are always present.
3218+ : If the server replied sending one or more headers, they are reported
3219+ : in an optional headers object. Each header is represented as a single (string)
3220+ : field.</p>
3221+ :
3222+ : <p>For non-multipart responses, as in the previous example, the response body,
3223+ : if any, is reported as a body object. This object contains both the (string)
3224+ : media-type returned by the server and its content.
3225+ : The type of the content field is determined by the media-type returned by the
3226+ : server. If the media-type indicates that the body content is textual,
3227+ : then the content has type string, base64Binary otherwise.
3228+ : Specifically, the body content is considered textual only if the MIME-type specified in
3229+ : the media-type is one of:
3230+ : <ul>
3231+ : <li>"application/json"</li>
3232+ : <li>"application/x-javascript"</li>
3233+ : <li>"application/xml"</li>
3234+ : <li>"application/xml-external-parsed-entity"</li>
3235+ : </ul>
3236+ : or if the MIME-type starts with "text/" or ends with "+xml".</p>
3237+ :
3238+ : <p>For multipart responses, multiple bodies are returned, as in the following example: </p>
3239+ :
3240+ : <pre>
3241+ : {
3242+ : "status" : 200,
3243+ : "message" : "OK",
3244+ : "headers" : {
3245+ : "Date" : "Tue, 11 Jun 2013 22:34:13 GMT",
3246+ : ...
3247+ : },
3248+ : "multipart" : {
3249+ : "boundary": "--AaB03x",
3250+ : "parts": [
3251+ : {
3252+ : "headers" : {
3253+ : "Content Disposition: file",
3254+ : ...
3255+ : },
3256+ : "body": {
3257+ : "media-type" : "image/gif",
3258+ : "content" : "..."
3259+ : }
3260+ : },
3261+ : {
3262+ : "body" : {
3263+ : "media-type" : "text/html",
3264+ : "content" : "..."
3265+ : }
3266+ : }
3267+ : ]
3268+ : }
3269+ : </pre>
3270+ :
3271+ : <p>The multipart field contains both the boundary used to separate parts
3272+ : and an array containing all parts. Each part contains its specific headers,
3273+ : if any, and the corresponding body.</p>
3274+ :
3275+ : <h2 id="nondeterministic_warning">Important Notice Regarding Nondeterministic Functions</h2>
3276+ :
3277+ : <p>
3278+ : The following functions in this module -
3279+ : <a href="#get-1">get#1</a>,
3280+ : <a href="#get-text-1">get-text#1</a>,
3281+ : <a href="#get-binary-1">get-binary#1</a>,
3282+ : <a href="#send-nondeterministic-request-1">send-nondeterministic-request-1</a>,
3283+ : <a href="#head-1">head#1</a>, and
3284+ : <a href="#options-1">options#1</a>
3285+ : are declared to be <i>nondeterministic</i>, which means that their results
3286+ : will not be cached.
3287+ : However, they are <b>not</b> declared to be
3288+ : <i>sequential</i>, which means that they may be re-ordered during query optimization.
3289+ : According to the HTTP RFC, GET, HEAD an OPTIONS requests should not have any side-effects.
3290+ : However, in practice it is not uncommon, especially for GET requests, to have side-effects.
3291+ : If your application depends on the ordering of side-effects from requests issued through
3292+ : these functions, you should either use the <a href="#send-request-3">send-request()</a>
3293+ : function (which is declared <i>sequential</i>), or alternatively
3294+ : wrap each call to get() in your own sequential function, to ensure
3295+ : that the requests are not reordered.
3296+ : </p>
3297+ :
3298+ : <h2 id="url_string">$href Arguments to Functions</h2>
3299+ :
3300+ : <p>Several functions in this module accept a URL argument named $href. In
3301+ : all cases, the value passed to $href must be a valid anyURI.
3302+ : However, all functions declare $href to be of type string. This
3303+ : is for convenience, since you can pass a string literal value (that
3304+ : is, a URL in double-quotes spelled out explicitly in your query)
3305+ : to an string parameter.</p>
3306+ :
3307+ : <h2 id="expath_relation">Relation to the EXPath http-client module</h2>
3308+ :
3309+ : <p><a href="http://expath.org/">EXPath</a> defines its own http-client
3310+ : module, which is available separately.
3311+ : There are two primary differences between EXPath's http-client and
3312+ : this module:
3313+ :
3314+ : <ol>
3315+ : <li>EXPath defines only the send-request() function, although it
3316+ : does include convenient 1- and 2-argument forms in addition to the
3317+ : full 3-argument form. EXPath does not include the simpler get(),
3318+ : post(), put(), delete(), head(), and options() functions defined by
3319+ : this module.</li>
3320+ : <li>EXPath uses XML to represent request for its send-request() function,
3321+ : whereas this module uses JSON.</li>
3322+ : <li>EXPath specifies that all XML content returned by an HTTP server
3323+ : will be parsed and returned as an XML document, whereas all HTML content
3324+ : will be <i>tidied up</i> into valid XML, and then parsed into an element.
3325+ : This module returns any textual content as string and any binary content
3326+ : as base6Binary.</li>
3327+ : <li>EXPath accepts XML nodes as body in the send-request() function and
3328+ : automatically serializes them into a string. The send-request() function
3329+ : defined in this module only allows string, base64Binary, and hexBinary
3330+ : as body types.
3331+ : </li>
3332+ : </ol>
3333+ : </p>
3334+ :
3335+ : <p>
3336+ : See <a href="http://www.expath.org/spec/http-client">the full spec
3337+ : of the EXPath http-client module</a> for more information.
3338+ : </p>
3339+ :
3340+ : @author Federico Cavalieri
3341+ : @see <a href="http://www.w3.org/TR/xquery-11/#FunctionDeclns">XQuery 1.1: Function Declaration</a>
3342+ : @library <a href="http://curl.haxx.se/">cURL Library</a>
3343+ : @project external
3344+ :)
3345+module namespace http = "http://zorba.io/modules/http-client";
3346+
3347+import module namespace libjn = "http://jsoniq.org/function-library";
3348+
3349+declare namespace an = "http://www.zorba-xquery.com/annotations";
3350+declare namespace ver = "http://www.zorba-xquery.com/options/versioning";
3351+declare namespace err = "http://www.w3.org/2005/xqt-errors";
3352+
3353+declare option ver:module-version "1.0";
3354+
3355+(:~
3356+ : <p>
3357+ : This function sends an HTTP request and returns the corresponding response.
3358+ : </p>
3359+ :
3360+ : <p>
3361+ : This function is declared as sequential and should be used whenever the
3362+ : request may have side-effects.
3363+ : </p>
3364+ :
3365+ : <p>
3366+ : The request parameters are specified in the $request JSON object, which
3367+ : has the following minimal structure:
3368+ :
3369+ : <pre>
3370+ : {
3371+ : "href": "http://www.example.com"
3372+ : }
3373+ : </pre>
3374+ : </p>
3375+ :
3376+ : <p>This object specifies a GET request of the URI "http://www.example.com"</p>
3377+ :
3378+ : <p>Additional optional parameters can be specified when issuing a request,
3379+ : using the following structure:</p>
3380+ : <pre>
3381+ : {
3382+ : "method": "POST",
3383+ : "href": "http://www.example.com",
3384+ : "authentication":
3385+ : {
3386+ : "username" : "user",
3387+ : "password" : "pass",
3388+ : "auth-method" : "Basic"
3389+ : },
3390+ : "options":
3391+ : {
3392+ : "status-only": true,
3393+ : "override-media-type": "text/plain",
3394+ : "follow-redirect": false,
3395+ : "timeout": 30,
3396+ : "user-agent": "Mozilla/5.0"
3397+ : },
3398+ : "headers":
3399+ : {
3400+ : "name": "value",
3401+ : ...
3402+ : },
3403+ : "body":
3404+ : {
3405+ : "media-type": "text/plain",
3406+ : "content": "..."
3407+ : }
3408+ : }
3409+ :</pre>
3410+ : <p>
3411+ : The method field (string) defines the HTTP verb to use in the HTTP request (i.e., GET, HEAD, OPTIONS,
3412+ : POST, PUT, DELETE). If not specified GET will be used.
3413+ : The authentication field can be used to specify the credentials and authentication method
3414+ : used when issuing a request (e.g, Basic). If the authentication field is specified, all its (string)
3415+ : subfields must be specified. If an authentication object is provided, it overrides any
3416+ : Authorization header specified in the request.
3417+ : Additionally, the following options can be specified:
3418+ : <ul>
3419+ : <li>status-only. If true, the response body contents are omitted from the response object.</li>
3420+ : <li>override-media-type. Is a MIME type that will override the Content-Type header returned
3421+ : by the server. It affects the type of the result body content.</li>
3422+ : <li>follow-redirect. Control whether an http redirect is automatically followed or not. If
3423+ : it is false, the http redirect is returned as the response. If it is
3424+ : true (the default) the function tries to follow the redirect, by
3425+ : sending the same request to the new address (including body, headers,
3426+ : and authentication credentials.) Maximum one redirect is followed
3427+ : (there is no attempt to follow a redirect in response to following a
3428+ : first redirect).</li>
3429+ : <li>timeout. Is the maximum number of seconds to wait for the server to respond.
3430+ : If no response is received withing this time duration, an error is thrown.</li>
3431+ : <li>user-agent. The user agent sent to the server when issuing the request.
3432+ : If not specified libcurl-agent/1.0 is used.</li>
3433+ : </ul>
3434+ : </p>
3435+ :
3436+ : <p>One or more headers can be sent to the server, specifying them in an optional headers object.
3437+ : Each header is represented as a single (string) field. These headers are overridden if the corresponding
3438+ : option/authentication has been specified in the request.</p>
3439+ :
3440+ : <p>For non-multipart request a body object can be specified.
3441+ : This object must contain both the desired (string) media-type and its content.
3442+ : The type of the content field must be either string, base64Binary, or hexBinary. </p>
3443+ :
3444+ : <p>For multipart requests, multipart object can be specified in place of the body object.
3445+ : The multipart object has the following structure: </p>
3446+ :
3447+ : <pre>
3448+ : "multipart" : {
3449+ : "boundary": "--AaB03x",
3450+ : "parts": [
3451+ : {
3452+ : "headers" : {
3453+ : "Content Disposition: file",
3454+ : ...
3455+ : },
3456+ : "body": {
3457+ : "media-type" : "image/gif",
3458+ : "content" : "..."
3459+ : }
3460+ : },
3461+ : {
3462+ : "body" : {
3463+ : "media-type" : "text/html",
3464+ : "content" : "..."
3465+ : }
3466+ : }
3467+ : ]
3468+ : }
3469+ : </pre>
3470+ :
3471+ : <p>The multipart field contains an optional (string) field which specifies
3472+ : the boundary used to separate each part and an array containing all parts.
3473+ : Each part contains its specific headers, if any, and the corresponding body.
3474+ : </p>
3475+ :
3476+ :
3477+ : @param $request a JSON http-client request object
3478+ : @return <a href="#standard_return">standard http-client return type</a>.
3479+ :
3480+ : @error http:HTTP An HTTP error occurred.
3481+ : @error http:REQUEST The specified request is not valid.
3482+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3483+ : @error http:FOLLOW Cannot follow a redirect of a POST, PUT, or DELETE request.
3484+ : @error http:CHARSET The specified charset is unsupported.
3485+ :
3486+ :)
3487+declare %an:sequential function http:send-request($request as object) as object
3488+{
3489+ if (http:check-request($request))
3490+ then http:http-sequential-impl($request)
3491+ else ()
3492+};
3493+
3494+(:~
3495+ : <p>
3496+ : This function sends an HTTP request and returns the corresponding response.
3497+ : </p>
3498+ : <p>
3499+ : This function has the same semantics of <a href="#send-request-1">send-request-1</a>,
3500+ : but is declared as nondeterministic and thus should only be used when
3501+ : the request has no side-effects.
3502+ : </p>
3503+ :
3504+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
3505+ : @param $request see request parameter of <a href="#send-request-1">send-request#1</a>
3506+ : @return <a href="#standard_return">standard http-client return type</a>.
3507+ :
3508+ : @error http:HTTP An HTTP error occurred.
3509+ : @error http:REQUEST The specified request is not valid.
3510+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3511+ : @error http:FOLLOW Cannot follow a redirect of a POST, PUT, or DELETE request.
3512+ : @error http:CHARSET The specified charset is unsupported.
3513+ :)
3514+declare %an:nondeterministic function http:send-nondeterministic-request($request as object) as object
3515+{
3516+ if (http:check-request($request))
3517+ then http:http-nondeterministic-impl($request)
3518+ else ()
3519+};
3520+
3521+
3522+(:~
3523+ : <p>
3524+ : This function makes a GET request to a given URL.
3525+ : </p>
3526+ :
3527+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
3528+ : @param $href The URL to which the request will be made (see
3529+ : <a href="#url_string">note</a> above).
3530+ : @return <a href="#standard_return">standard http-client return type</a>.
3531+ :
3532+ : @error http:HTTP An HTTP error occurred.
3533+ : @error http:REQUEST The specified href is not valid.
3534+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3535+ :)
3536+declare %an:nondeterministic function http:get($href as string) as object
3537+{
3538+ http:send-nondeterministic-request(
3539+ {
3540+ "method" : "GET",
3541+ "href": $href
3542+ })
3543+};
3544+
3545+(:~
3546+ : <p>
3547+ : This function makes a GET request to a given URL. All returned bodies
3548+ : are forced to be interpreted as textual, with a UTF-8 charset and will
3549+ : be returned as string items.
3550+ : </p>
3551+ :
3552+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
3553+ : @param $href The URL to which the request will be made (see
3554+ : <a href="#url_string">note</a> above).
3555+ : @return <a href="#standard_return">standard http-client return type</a>.
3556+ :
3557+ : @error http:HTTP An HTTP error occurred.
3558+ : @error http:REQUEST The specified href is not valid.
3559+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3560+ :
3561+ :)
3562+declare %an:nondeterministic function http:get-text($href as string) as object
3563+{
3564+ http:send-nondeterministic-request(
3565+ {
3566+ "method": "GET",
3567+ "href": $href,
3568+ "options": {
3569+ "override-media-type": "text/plain; charset=utf-8"
3570+ }
3571+ })
3572+};
3573+
3574+(:~
3575+ : <p>
3576+ : This function makes a GET request on a given URL. All returned bodies
3577+ : are forced to be interpreted as binary data, and will be returned
3578+ : as base64Binary items.
3579+ : </p>
3580+ :
3581+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
3582+ : @param $href The URL to which the request will be made (see
3583+ : <a href="#url_string">note</a> above).
3584+ : @return <a href="#standard_return">standard http-client return type</a>.
3585+ :
3586+ : @error http:HTTP An HTTP error occurred.
3587+ : @error http:REQUEST The specified href is not valid.
3588+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3589+ :
3590+ :)
3591+declare %an:nondeterministic function http:get-binary($href as string) as object
3592+{
3593+ http:send-nondeterministic-request(
3594+ {
3595+ "method": "GET",
3596+ "href": $href,
3597+ "options": {
3598+ "override-media-type": "binary"
3599+ }
3600+ })
3601+};
3602+
3603+(:~
3604+ : <p>
3605+ : This function makes an HTTP HEAD request on a given URL.
3606+ : </p>
3607+ :
3608+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
3609+ : @param $href The URL to which the request will be made (see
3610+ : <a href="#url_string">note</a> above).
3611+ : @return <a href="#standard_return">standard http-client return type</a>.
3612+ :
3613+ : @error http:HTTP An HTTP error occurred.
3614+ : @error http:REQUEST The specified href is not valid.
3615+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3616+ :
3617+ :)
3618+declare %an:nondeterministic function http:head($href as string) as object
3619+{
3620+ http:send-nondeterministic-request(
3621+ {
3622+ "method": "HEAD",
3623+ "href": $href
3624+ })
3625+};
3626+
3627+(:~
3628+ : <p>
3629+ : This function makes an HTTP OPTIONS request, which asks the server
3630+ : which operations it supports.
3631+ : </p>
3632+ :
3633+ : @see <a href="#nondeterministic_warning">Notice about nondeterministic functions</a>
3634+ : @param $href The URL to which the request will be made (see
3635+ : <a href="#url_string">note</a> above).
3636+ : @return A sequence of string values of the allowed operations.
3637+ :
3638+ : @error http:HTTP An HTTP error occurred.
3639+ : @error http:REQUEST The specified href is not valid.
3640+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3641+ :
3642+ :)
3643+declare %an:nondeterministic function http:options($href as string) as string*
3644+{
3645+ let $resp := http:send-nondeterministic-request(
3646+ {
3647+ "method": "OPTIONS",
3648+ "href": $href
3649+ })[1]
3650+ return
3651+ fn:tokenize($resp.headers.Allow, ",")
3652+};
3653+
3654+
3655+(:~
3656+ : <p>
3657+ : This function makes an HTTP PUT request to a given URL.
3658+ : </p>
3659+ : <p>
3660+ : The body passed to this function must be either a string, a base64Binary or
3661+ : an hexBinary.
3662+ : If it is a string, the Content-Type sent to the server will be "text/plain",
3663+ : "application/octet-stream" otherwise.
3664+ : </p>
3665+ :
3666+ : @param $href The URL to which the request will be made (see
3667+ : <a href="#url_string">note</a> above).
3668+ : @param $body The body which will be sent to the server.
3669+ : @return <a href="#standard_return">standard http-client return type</a>.
3670+ :
3671+ : @error http:HTTP An HTTP error occurred.
3672+ : @error http:REQUEST The specified request is not valid.
3673+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3674+ :
3675+ :)
3676+declare %an:sequential function http:put($href as string, $body as atomic) as object
3677+{
3678+ variable $media-type as string :=
3679+ typeswitch($body)
3680+ case string return "text/plain"
3681+ case base64Binary return "application/octet-stream"
3682+ case hexBinary return "application/octet-stream"
3683+ default return fn:error(QName("http:REQUEST"), "The specified request is not valid. The type of the request body must be string, base64Binary, or hexBinary.");
3684+ http:put($href, $body, $media-type)
3685+};
3686+
3687+(:~
3688+ : <p>
3689+ : This function makes an HTTP PUT request to a given URL.
3690+ : </p>
3691+ : <p>
3692+ : The body passed to this function must be either a string, a base64Binary, or
3693+ : an hexBinary.
3694+ : In any case, Content-Type of the request sent to the server will
3695+ : be $content-type.
3696+ : </p>
3697+ :
3698+ : @param $href The URL to which the request will be made (see
3699+ : <a href="#url_string">note</a> above).
3700+ : @param $body The body which will be sent to the server.
3701+ : @param $content-type The content type of $body to send to the server.
3702+ : @return <a href="#standard_return">standard http-client return type</a>.
3703+ :
3704+ : @error http:HTTP An HTTP error occurred.
3705+ : @error http:REQUEST The specified request is not valid.
3706+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3707+ : @error http:CHARSET The specified charset is unsupported.
3708+ :
3709+ :)
3710+declare %an:sequential function http:put($href as string, $body as atomic, $content-type as string) as object
3711+{
3712+ http:send-request(
3713+ {
3714+ "method": "PUT",
3715+ "href": $href,
3716+ "body": {
3717+ "media-type": $content-type,
3718+ "content": $body
3719+ }
3720+ })
3721+};
3722+
3723+(:~
3724+ : <p>
3725+ : This function makes an HTTP DELETE request to a given URL.
3726+ : </p>
3727+ :
3728+ : @param $href The URL to which the request will be made (see
3729+ : <a href="#url_string">note</a> above).
3730+ : @return <a href="#standard_return">standard http-client return type</a>.
3731+ :
3732+ : @error http:HTTP An HTTP error occurred.
3733+ : @error http:REQUEST The specified request is not valid.
3734+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3735+ :
3736+ :)
3737+declare %an:sequential function http:delete($href as string) as object
3738+{
3739+ http:send-request(
3740+ {
3741+ "method": "DELETE",
3742+ "href": $href
3743+ })
3744+};
3745+
3746+(:~
3747+ : <p>
3748+ : This function makes an HTTP POST request to a given URL.
3749+ : </p>
3750+ : <p>
3751+ : The body passed to this function must be either a string, a base64Binary, or an
3752+ : hexBinary.
3753+ : If it is a string, the Content-Type sent to the server will be "text/plain",
3754+ : "application/octet-stream" otherwise.
3755+ : </p>
3756+ :
3757+ : @param $href The URL to which the request will be made (see
3758+ : <a href="#url_string">note</a> above).
3759+ : @param $body The body which will be sent to the server.
3760+ : @return <a href="#standard_return">standard http-client return type</a>.
3761+ :
3762+ : @error http:HTTP An HTTP error occurred.
3763+ : @error http:REQUEST The specified request is not valid.
3764+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3765+ :
3766+ :)
3767+declare %an:sequential function http:post($href as string, $body as atomic) as object
3768+{
3769+ variable $media-type as string :=
3770+ typeswitch($body)
3771+ case string return "text/plain"
3772+ case base64Binary return "application/octet-stream"
3773+ case hexBinary return "application/octet-stream"
3774+ default return fn:error(QName("http:REQUEST"), "The specified request is not valid. The type of the request body must be string, base64Binary, or hexBinary.");
3775+
3776+ http:post($href, $body, $media-type)
3777+};
3778+
3779+(:~
3780+ : <p>
3781+ : This function makes an HTTP POST request to a given URL.
3782+ : </p>
3783+ : <p>
3784+ : The body passed to this function must be either a string, a base64Binary,
3785+ : or an hexBinary.
3786+ : In any case, Content-Type of the request sent to the server will
3787+ : be $content-type.
3788+ : </p>
3789+ :
3790+ : @param $href The URL to which the request will be made (see
3791+ : <a href="#url_string">note</a> above).
3792+ : @param $body The body which will be sent to the server
3793+ : @param $content-type The content type of the body as described above.
3794+ : @return <a href="#standard_return">standard http-client return type</a>.
3795+ :
3796+ : @error http:HTTP An HTTP error occurred.
3797+ : @error http:REQUEST The specified request is not valid.
3798+ : @error http:TIMEOUT A timeout occurred waiting for the response.
3799+ : @error http:CHARSET The specified charset is unsupported.
3800+ :
3801+ :)
3802+declare %an:sequential function http:post($href as string, $body as atomic, $content-type as string) as object
3803+{
3804+ http:send-request(
3805+ {
3806+ "method": "POST",
3807+ "href": $href,
3808+ "body": {
3809+ "media-type": $content-type,
3810+ "content": $body
3811+ }
3812+ })
3813+};
3814+
3815+
3816+(:~
3817+ : Private function used internally by this module.
3818+ :
3819+ : This function checks if the request, href, and bodies parameters
3820+ : are consistent.
3821+ :
3822+ : @error http:REQUEST The specified request is not valid.
3823+ :)
3824+declare %private function http:check-request($request as object) as boolean
3825+{
3826+ for $body in libjn:descendant-objects($request).body
3827+ return
3828+ (
3829+ if (exists($body.src) and exists($body.content))
3830+ then fn:error(QName("http:REQUEST"), "The specified request is not valid. The src and content fields are mutually exclusive.")
3831+ else (),
3832+ if (exists($body.content))
3833+ then
3834+ typeswitch($body.content)
3835+ case string return ()
3836+ case base64Binary return ()
3837+ case hexBinary return ()
3838+ default return fn:error(QName("http:REQUEST"), "The specified request is not valid. The type of the body content must be string, base64Binary, or hexBinary.")
3839+ else ()
3840+ ),
3841+ if (count(libjn:descendant-objects($request).body[exists($$.src) and exists($$.content)]) gt 1)
3842+ then fn:error(QName("http:REQUEST"), "The specified request is not valid. The src and content fields are mutually exclusive.")
3843+ else if (exists($request.href) and not($request.href castable as anyURI))
3844+ then fn:error(QName("http:REQUEST"), "he specified request is not valid. The specified href is not a valid anyURI.")
3845+ else (),
3846+ fn:true()
3847+};
3848+
3849+declare %private %an:sequential function http:http-sequential-impl($request as object) as object external;
3850+
3851+declare %private %an:nondeterministic function http:http-nondeterministic-impl($request as object) as object external;
3852
3853=== added directory 'modules/http-client/json/http-client.xq.src'
3854=== added file 'modules/http-client/json/http-client.xq.src/curl_stream_buffer.cpp'
3855--- modules/http-client/json/http-client.xq.src/curl_stream_buffer.cpp 1970-01-01 00:00:00 +0000
3856+++ modules/http-client/json/http-client.xq.src/curl_stream_buffer.cpp 2013-07-25 09:33:27 +0000
3857@@ -0,0 +1,379 @@
3858+/*
3859+ * Copyright 2006-2013 The FLWOR Foundation.
3860+ *
3861+ * Licensed under the Apache License, Version 2.0 (the "License");
3862+ * you may not use this file except in compliance with the License.
3863+ * You may obtain a copy of the License at
3864+ *
3865+ * http://www.apache.org/licenses/LICENSE-2.0
3866+ *
3867+ * Unless required by applicable law or agreed to in writing, software
3868+ * distributed under the License is distributed on an "AS IS" BASIS,
3869+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3870+ * See the License for the specific language governing permissions and
3871+ * limitations under the License.
3872+ */
3873+
3874+#include <zorba/config.h>
3875+
3876+#include <cstdlib>
3877+#include <cstring> /* for memcpy(3) */
3878+#include <iostream>
3879+#include <cassert>
3880+#ifndef WIN32
3881+#include <cerrno>
3882+#include <sys/time.h>
3883+#endif /* WIN32 */
3884+
3885+#include <curl/multi.h>
3886+
3887+#include "curl_stream_buffer.h"
3888+#include "inform_data_read.h"
3889+
3890+using namespace std;
3891+
3892+namespace zorba {
3893+namespace curl {
3894+
3895+///////////////////////////////////////////////////////////////////////////////
3896+
3897+#define ZORBA_CURL_ASSERT(expr) \
3898+ do { \
3899+ if ( CURLcode const code##__LINE__ = (expr) ) \
3900+ throw exception( #expr, "", code##__LINE__ ); \
3901+ } while (0)
3902+
3903+#define ZORBA_CURLM_ASSERT(expr) \
3904+ do { \
3905+ if ( CURLMcode const code##__LINE__ = (expr) ) \
3906+ if ( code##__LINE__ != CURLM_CALL_MULTI_PERFORM ) \
3907+ throw exception( #expr, "", code##__LINE__ ); \
3908+ } while (0)
3909+
3910+exception::exception( char const *function, char const *uri, char const *msg ) :
3911+ std::exception(), msg_( msg )
3912+{
3913+}
3914+
3915+exception::exception( char const *function, char const *uri, CURLcode code ) :
3916+ std::exception(),
3917+ msg_( curl_easy_strerror( code ) )
3918+{
3919+}
3920+
3921+exception::exception( char const *function, char const *uri, CURLMcode code ) :
3922+ std::exception(),
3923+ msg_( curl_multi_strerror( code ) )
3924+{
3925+}
3926+
3927+exception::~exception() throw() {
3928+ // out-of-line since it's virtual
3929+}
3930+
3931+const char* exception::what() const throw() {
3932+ return msg_.c_str();
3933+}
3934+
3935+///////////////////////////////////////////////////////////////////////////////
3936+
3937+CURL* create( char const *uri, write_fn_t fn, void *data ) {
3938+ //
3939+ // Having cURL initialization wrapped by a class and using a singleton static
3940+ // instance guarantees that cURL is initialized exactly once before use and
3941+ // and also is cleaned-up at program termination (when destructors for static
3942+ // objects are called).
3943+ //
3944+ struct curl_initializer {
3945+ curl_initializer() {
3946+ ZORBA_CURL_ASSERT( curl_global_init( CURL_GLOBAL_ALL ) );
3947+ }
3948+ ~curl_initializer() {
3949+ curl_global_cleanup();
3950+ }
3951+ };
3952+ static curl_initializer initializer;
3953+
3954+ CURL *const curl = curl_easy_init();
3955+ if ( !curl )
3956+ throw exception( "curl_easy_init()", uri, "" );
3957+
3958+ try {
3959+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_URL, uri ) );
3960+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEDATA, data ) );
3961+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, fn ) );
3962+
3963+ // Tells cURL to follow redirects. CURLOPT_MAXREDIRS is by default set to -1
3964+ // thus cURL will do an infinite number of redirects.
3965+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1 ) );
3966+
3967+#ifndef ZORBA_VERIFY_PEER_SSL_CERTIFICATE
3968+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 0 ) );
3969+ //
3970+ // CURLOPT_SSL_VERIFYHOST is left default, value 2, meaning verify that the
3971+ // Common Name or Subject Alternate Name field in the certificate matches
3972+ // the name of the server.
3973+ //
3974+ // Tested with https://www.npr.org/rss/rss.php?id=1001
3975+ // About using SSL certs in curl: http://curl.haxx.se/docs/sslcerts.html
3976+#else
3977+# ifdef WIN32
3978+ // set the root CA certificates file path
3979+ if ( GENV.g_curl_root_CA_certificates_path[0] )
3980+ ZORBA_CURL_ASSERT(
3981+ curl_easy_setopt(
3982+ curl, CURLOPT_CAINFO, GENV.g_curl_root_CA_certificates_path
3983+ )
3984+ );
3985+# endif /* WIN32 */
3986+#endif /* ZORBA_VERIFY_PEER_SSL_CERTIFICATE */
3987+
3988+ //
3989+ // Some servers don't like requests that are made without a user-agent
3990+ // field, so we provide one.
3991+ //
3992+ //ZORBA_CURL_ASSERT(
3993+ //curl_easy_setopt( curl, CURLOPT_USERAGENT, "libcurl-agent/1.0" )
3994+ //);
3995+
3996+ return curl;
3997+ }
3998+ catch ( ... ) {
3999+ destroy( curl );
4000+ throw;
4001+ }
4002+}
4003+
4004+void destroy( CURL *curl ) {
4005+ if ( curl ) {
4006+ curl_easy_reset( curl );
4007+ curl_easy_cleanup( curl );
4008+ }
4009+}
4010+
4011+///////////////////////////////////////////////////////////////////////////////
4012+
4013+streambuf::streambuf() {
4014+ init();
4015+}
4016+
4017+streambuf::streambuf( char const *uri ) {
4018+ init();
4019+ open( uri );
4020+}
4021+
4022+streambuf::streambuf( CURL *curl ) {
4023+ init();
4024+ curl_ = curl;
4025+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEDATA, this ) );
4026+ ZORBA_CURL_ASSERT( curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, curl_write_callback ) );
4027+ init_curlm();
4028+}
4029+
4030+streambuf::~streambuf() {
4031+ free( buf_ );
4032+ close();
4033+#ifdef WIN32
4034+ closesocket( dummy_socket_ );
4035+#endif
4036+ // If we have been assigned memory ownership of theInformer, delete it now.
4037+ if ( theOwnInformer )
4038+ delete theInformer;
4039+}
4040+
4041+void streambuf::close() {
4042+ if ( curl_ ) {
4043+ if ( curlm_ ) {
4044+ curl_multi_remove_handle( curlm_, curl_ );
4045+ curl_multi_cleanup( curlm_ );
4046+ curlm_ = 0;
4047+ }
4048+ destroy( curl_ );
4049+ curl_ = 0;
4050+ }
4051+}
4052+
4053+void streambuf::curl_read() {
4054+ buf_len_ = 0;
4055+ while ( curl_running_ && !buf_len_ ) {
4056+ fd_set fd_read, fd_write, fd_except;
4057+ FD_ZERO( &fd_read );
4058+ FD_ZERO( &fd_write );
4059+ FD_ZERO( &fd_except );
4060+ int max_fd = -1;
4061+#ifdef WIN32
4062+ //
4063+ // Windows does not like a call to select where all arguments are 0, so we
4064+ // just add a dummy socket to make the call to select happy.
4065+ //
4066+ FD_SET( dummy_socket_, &fd_read );
4067+#endif /* WIN32 */
4068+ ZORBA_CURLM_ASSERT(
4069+ curl_multi_fdset( curlm_, &fd_read, &fd_write, &fd_except, &max_fd )
4070+ );
4071+
4072+ //
4073+ // Note that the fopen.c sample code is unnecessary at best or wrong at
4074+ // worst; see: http://curl.haxx.se/mail/lib-2011-05/0011.html
4075+ //
4076+ timeval timeout;
4077+ long curl_timeout_ms;
4078+ ZORBA_CURLM_ASSERT( curl_multi_timeout( curlm_, &curl_timeout_ms ) );
4079+ if ( curl_timeout_ms > 0 ) {
4080+ timeout.tv_sec = curl_timeout_ms / 1000;
4081+ timeout.tv_usec = curl_timeout_ms % 1000 * 1000;
4082+ } else {
4083+ //
4084+ // From curl_multi_timeout(3):
4085+ //
4086+ // Note: if libcurl returns a -1 timeout here, it just means that
4087+ // libcurl currently has no stored timeout value. You must not wait
4088+ // too long (more than a few seconds perhaps) before you call
4089+ // curl_multi_perform() again.
4090+ //
4091+ // So we just pick some not-too-long default.
4092+ //
4093+ timeout.tv_sec = 1;
4094+ timeout.tv_usec = 0;
4095+ }
4096+
4097+ switch ( select( max_fd + 1, &fd_read, &fd_write, &fd_except, &timeout ) ) {
4098+ case -1: // select error
4099+#ifdef WIN32
4100+ char err_buf[8];
4101+ sprintf( err_buf, "%d", WSAGetLastError() );
4102+ throw exception( "select()", "", err_buf );
4103+#else
4104+ throw exception( "select()", "", strerror( errno ) );
4105+#endif
4106+ case 0: // timeout
4107+ // no break;
4108+ default:
4109+ CURLMcode code;
4110+ do {
4111+ code = curl_multi_perform( curlm_, &curl_running_ );
4112+ } while ( code == CURLM_CALL_MULTI_PERFORM );
4113+ ZORBA_CURLM_ASSERT( code );
4114+ }
4115+ }
4116+ if ( theInformer )
4117+ theInformer->afterRead();
4118+}
4119+
4120+size_t streambuf::curl_write_callback( void *ptr, size_t size, size_t nmemb,
4121+ void *data ) {
4122+ size *= nmemb;
4123+ streambuf *const that = static_cast<streambuf*>( data );
4124+
4125+ if ( that->theInformer )
4126+ that->theInformer->beforeRead();
4127+
4128+ size_t const buf_free = that->buf_capacity_ - that->buf_len_;
4129+ if ( size > buf_free ) {
4130+ streamoff new_capacity = that->buf_capacity_ + size - buf_free;
4131+ if ( void *const new_buf =
4132+ realloc( that->buf_, static_cast<size_t>( new_capacity ) ) ) {
4133+ that->buf_ = static_cast<char*>( new_buf );
4134+ that->buf_capacity_ = new_capacity;
4135+ } else
4136+ throw exception( "realloc()", "" );
4137+ }
4138+ ::memcpy( that->buf_ + that->buf_len_, ptr, size );
4139+ that->buf_len_ += size;
4140+ return size;
4141+}
4142+
4143+void streambuf::init() {
4144+ buf_ = 0;
4145+ buf_capacity_ = 0;
4146+ buf_len_ = 0;
4147+ curl_ = 0;
4148+ curlm_ = 0;
4149+ curl_running_ = 0;
4150+ theInformer = 0;
4151+ theOwnInformer = false;
4152+#ifdef WIN32
4153+ dummy_socket_ = socket( AF_INET, SOCK_DGRAM, 0 );
4154+ if ( dummy_socket_ == CURL_SOCKET_BAD || dummy_socket_ == INVALID_SOCKET )
4155+ throw exception( "socket()", "" );
4156+#endif /* WIN32 */
4157+}
4158+
4159+void streambuf::init_curlm() {
4160+ //
4161+ // Lie about cURL running initially so the while-loop in curl_read() will run
4162+ // at least once.
4163+ //
4164+ curl_running_ = 1;
4165+
4166+ //
4167+ // Set the "get" pointer to the end (gptr() == egptr()) so a call to
4168+ // underflow() and initial data read will be triggered.
4169+ //
4170+ buf_len_ = buf_capacity_;
4171+ setg( buf_, buf_ + buf_len_, buf_ + buf_capacity_ );
4172+
4173+ //
4174+ // Clean-up has to be done here with try/catch (as opposed to relying on the
4175+ // destructor) because open() can be called from the constructor. If an
4176+ // exception is thrown, the constructor will not have completed, hence the
4177+ // object will not have been fully constructed; therefore the destructor will
4178+ // not be called.
4179+ //
4180+ try {
4181+ if ( !(curlm_ = curl_multi_init()) )
4182+ throw exception( "curl_multi_init()", "" );
4183+ try {
4184+ ZORBA_CURLM_ASSERT( curl_multi_add_handle( curlm_, curl_ ) );
4185+ }
4186+ catch ( ... ) {
4187+ curl_multi_cleanup( curlm_ );
4188+ curlm_ = 0;
4189+ throw;
4190+ }
4191+ }
4192+ catch ( ... ) {
4193+ destroy( curl_ );
4194+ curl_ = 0;
4195+ throw;
4196+ }
4197+}
4198+
4199+int streambuf::multi_perform() {
4200+ underflow();
4201+ CURLMsg *msg;
4202+ int msgInQueue;
4203+ int error = 0;
4204+ while ( (msg = curl_multi_info_read( curlm_, &msgInQueue )) ) {
4205+ if ( msg->msg == CURLMSG_DONE )
4206+ error = msg->data.result;
4207+ }
4208+ return error;
4209+}
4210+
4211+void streambuf::open( char const *uri ) {
4212+ curl_ = create( uri, curl_write_callback, this );
4213+
4214+ init_curlm();
4215+}
4216+
4217+streamsize streambuf::showmanyc() {
4218+ return egptr() - gptr();
4219+}
4220+
4221+streambuf::int_type streambuf::underflow() {
4222+ while ( true ) {
4223+ if ( gptr() < egptr() )
4224+ return traits_type::to_int_type( *gptr() );
4225+ curl_read();
4226+ if ( !buf_len_ )
4227+ return traits_type::eof();
4228+ setg( buf_, buf_, buf_ + buf_len_ );
4229+ }
4230+}
4231+
4232+///////////////////////////////////////////////////////////////////////////////
4233+
4234+} // namespace curl
4235+} // namespace zorba
4236+/* vim:set et sw=2 ts=2: */
4237
4238=== added file 'modules/http-client/json/http-client.xq.src/curl_stream_buffer.h'
4239--- modules/http-client/json/http-client.xq.src/curl_stream_buffer.h 1970-01-01 00:00:00 +0000
4240+++ modules/http-client/json/http-client.xq.src/curl_stream_buffer.h 2013-07-25 09:33:27 +0000
4241@@ -0,0 +1,193 @@
4242+/*
4243+ * Copyright 2006-2013 The FLWOR Foundation.
4244+ *
4245+ * Licensed under the Apache License, Version 2.0 (the "License");
4246+ * you may not use this file except in compliance with the License.
4247+ * You may obtain a copy of the License at
4248+ *
4249+ * http://www.apache.org/licenses/LICENSE-2.0
4250+ *
4251+ * Unless required by applicable law or agreed to in writing, software
4252+ * distributed under the License is distributed on an "AS IS" BASIS,
4253+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4254+ * See the License for the specific language governing permissions and
4255+ * limitations under the License.
4256+ */
4257+#pragma once
4258+#ifndef ZORBA_CURL_UTIL_H
4259+#define ZORBA_CURL_UTIL_H
4260+
4261+#include <zorba/config.h>
4262+
4263+#include <exception>
4264+#include <istream>
4265+#include <streambuf>
4266+#include <string>
4267+#include <curl/curl.h>
4268+
4269+namespace zorba {
4270+
4271+namespace http_client {
4272+ class InformDataRead;
4273+}
4274+
4275+namespace curl {
4276+
4277+///////////////////////////////////////////////////////////////////////////////
4278+
4279+class exception : public std::exception {
4280+public:
4281+ exception( char const *function, char const *uri, char const *msg = 0 );
4282+ exception( char const *function, char const *uri, CURLcode code );
4283+ exception( char const *function, char const *uri, CURLMcode code );
4284+ ~exception() throw();
4285+
4286+ virtual const char* what() const throw();
4287+
4288+private:
4289+ std::string msg_;
4290+};
4291+
4292+////////// create & destroy ///////////////////////////////////////////////////
4293+
4294+/**
4295+ * The signature type of cURL's write function callback.
4296+ */
4297+typedef size_t (*write_fn_t)( void*, size_t, size_t, void* );
4298+
4299+/**
4300+ * Creates a new, initialized cURL instance.
4301+ *
4302+ * @throws exception upon failure.
4303+ */
4304+CURL* create( char const *uri, write_fn_t fn, void *data );
4305+
4306+/**
4307+ * Destroys a cURL instance.
4308+ *
4309+ * @param instance A cURL instance. If \c NULL, does nothing.
4310+ */
4311+void destroy( CURL *instance );
4312+
4313+////////// streambuf //////////////////////////////////////////////////////////
4314+
4315+/**
4316+ * A curl::streambuf is-a std::streambuf for streaming the contents of URI
4317+ * using cURL. However, do not use this class directly. Use uri::streambuf
4318+ * instead.
4319+ */
4320+class streambuf : public std::streambuf {
4321+public:
4322+ /**
4323+ * Constructs a %streambuf.
4324+ */
4325+ streambuf();
4326+
4327+ /**
4328+ * Constructs a %streambuf and opens a connection to the server hosting the
4329+ * given URI for subsequent streaming.
4330+ *
4331+ * @param uri The URI to stream.
4332+ */
4333+ streambuf( char const *uri );
4334+
4335+ /**
4336+ * Constructs a %streambuf using an existing CURL object.
4337+ *
4338+ * @param curl The CURL object to use. This %streambuf takes ownership of
4339+ * it.
4340+ */
4341+ streambuf( CURL *curl );
4342+
4343+ /**
4344+ * Destroys a %streambuf.
4345+ */
4346+ ~streambuf();
4347+
4348+ /**
4349+ * Opens a connection to the server hosting the given URI for subsequent
4350+ * streaming.
4351+ *
4352+ * @param uri The URI to stream.
4353+ * @throws exception upon failure.
4354+ */
4355+ void open( char const *uri );
4356+
4357+ /**
4358+ * Tests whether the buffer is open.
4359+ *
4360+ * @return Returns \c true only if the buffer is open.
4361+ */
4362+ bool is_open() const {
4363+ return !!curl_;
4364+ }
4365+
4366+ /**
4367+ * Closes this %streambuf.
4368+ */
4369+ void close();
4370+
4371+ /**
4372+ * Gets the CURL object in use.
4373+ *
4374+ * @return Return said CURL object.
4375+ */
4376+ CURL* curl() const {
4377+ return curl_;
4378+ }
4379+
4380+ /**
4381+ * Provide a InformDataRead that will get callbacks about read events.
4382+ */
4383+ void setInformer( http_client::InformDataRead *aInformer ) {
4384+ theInformer = aInformer;
4385+ }
4386+
4387+ /**
4388+ * Specify whether this streambuf has memory ownership over the
4389+ * InformDataRead it has been passed. You can use this if, for example,
4390+ * the lifetime of the streambuf will extend past the lifetime of the
4391+ * object which created the InformDataRead.
4392+ */
4393+ void setOwnInformer( bool aOwnInformer ) {
4394+ theOwnInformer = aOwnInformer;
4395+ }
4396+
4397+ int multi_perform();
4398+
4399+protected:
4400+ // inherited
4401+ std::streamsize showmanyc();
4402+ int_type underflow();
4403+
4404+private:
4405+ void curl_read();
4406+ static size_t curl_write_callback( void*, size_t, size_t, void* );
4407+
4408+ void init();
4409+ void init_curlm();
4410+
4411+ char *buf_;
4412+ std::streamsize buf_capacity_;
4413+ std::streamoff buf_len_;
4414+
4415+ CURL *curl_;
4416+ CURLM *curlm_;
4417+ int curl_running_;
4418+ http_client::InformDataRead *theInformer;
4419+ bool theOwnInformer;
4420+
4421+ // forbid
4422+ streambuf( streambuf const& );
4423+ streambuf& operator=( streambuf const& );
4424+#ifdef WIN32
4425+ SOCKET dummy_socket_;
4426+#endif /* WIN32 */
4427+};
4428+
4429+///////////////////////////////////////////////////////////////////////////////
4430+
4431+} // namespace curl
4432+} // namespace zorba
4433+#endif /* ZORBA_CURL_UTIL_H */
4434+/* vim:set et sw=2 ts=2: */
4435
4436=== added file 'modules/http-client/json/http-client.xq.src/error_thrower.h'
4437--- modules/http-client/json/http-client.xq.src/error_thrower.h 1970-01-01 00:00:00 +0000
4438+++ modules/http-client/json/http-client.xq.src/error_thrower.h 2013-07-25 09:33:27 +0000
4439@@ -0,0 +1,66 @@
4440+/*
4441+ * Copyright 2006-2013 The FLWOR Foundation.
4442+ *
4443+ * Licensed under the Apache License, Version 2.0 (the "License");
4444+ * you may not use this file except in compliance with the License.
4445+ * You may obtain a copy of the License at
4446+ *
4447+ * http://www.apache.org/licenses/LICENSE-2.0
4448+ *
4449+ * Unless required by applicable law or agreed to in writing, software
4450+ * distributed under the License is distributed on an "AS IS" BASIS,
4451+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4452+ * See the License for the specific language governing permissions and
4453+ * limitations under the License.
4454+ */
4455+
4456+#pragma once
4457+#include <zorba/zorba.h>
4458+#include <zorba/user_exception.h>
4459+#include <curl/curl.h>
4460+
4461+namespace zorba {
4462+namespace http_client {
4463+
4464+class ErrorThrower
4465+{
4466+private:
4467+ ItemFactory* theFactory;
4468+ struct curl_slist** theHeaderList;
4469+ const String& theModuleURI;
4470+
4471+public:
4472+ ErrorThrower(ItemFactory* aFactory, struct curl_slist** aHeaderList, const String& aModuleURI)
4473+ :
4474+ theFactory(aFactory),
4475+ theHeaderList(aHeaderList),
4476+ theModuleURI(aModuleURI)
4477+ {
4478+ }
4479+
4480+ void raiseException( String const &aNamespace, String const &aLocalName,
4481+ String const &aDescription )
4482+ {
4483+ if (*theHeaderList)
4484+ curl_slist_free_all(*theHeaderList);
4485+
4486+ throw USER_EXCEPTION(
4487+ theFactory->createQName(aNamespace, aLocalName), aDescription
4488+ );
4489+ }
4490+
4491+ void raiseException( String const &aLocalName,
4492+ String const &aDescription )
4493+ {
4494+ if (*theHeaderList)
4495+ curl_slist_free_all(*theHeaderList);
4496+
4497+ throw USER_EXCEPTION(
4498+ theFactory->createQName(theModuleURI, aLocalName), aDescription
4499+ );
4500+ }
4501+};
4502+
4503+} // namespace http_client
4504+} // namespace zorba
4505+/* vim:set et sw=2 ts=2: */
4506
4507=== added file 'modules/http-client/json/http-client.xq.src/http_client.cpp'
4508--- modules/http-client/json/http-client.xq.src/http_client.cpp 1970-01-01 00:00:00 +0000
4509+++ modules/http-client/json/http-client.xq.src/http_client.cpp 2013-07-25 09:33:27 +0000
4510@@ -0,0 +1,255 @@
4511+/*
4512+ * Copyright 2006-2013 The FLWOR Foundation.
4513+ *
4514+ * Licensed under the Apache License, Version 2.0 (the "License");
4515+ * you may not use this file except in compliance with the License.
4516+ * You may obtain a copy of the License at
4517+ *
4518+ * http://www.apache.org/licenses/LICENSE-2.0
4519+ *
4520+ * Unless required by applicable law or agreed to in writing, software
4521+ * distributed under the License is distributed on an "AS IS" BASIS,
4522+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4523+ * See the License for the specific language governing permissions and
4524+ * limitations under the License.
4525+ */
4526+#include <curl/curl.h>
4527+#include <map>
4528+#include <zorba/zorba.h>
4529+#include <zorba/serializer.h>
4530+#include <zorba/external_module.h>
4531+#include <zorba/function.h>
4532+#include <zorba/empty_sequence.h>
4533+#include <zorba/user_exception.h>
4534+
4535+#include "http_request_handler.h"
4536+#include "request_parser.h"
4537+#include "http_response_handler.h"
4538+#include "http_response_parser.h"
4539+
4540+#ifdef WIN32
4541+# include <Windows.h>
4542+# define MAX_BUF_SIZE 2048
4543+#endif
4544+
4545+namespace zorba {
4546+
4547+ namespace http_client {
4548+#ifdef WIN32
4549+static void set_cacert(CURL* lCurl, std::string aPath)
4550+{
4551+ TCHAR path[MAX_BUF_SIZE];
4552+ int r = GetModuleFileName(NULL, path, 2048);
4553+ if (r == -1)
4554+ return;
4555+# ifdef UNICODE
4556+ char buf[MAX_BUF_SIZE];
4557+ memset(buf, 0, MAX_BUF_SIZE);
4558+ for (int i = 0; i <= r; ++i)
4559+ {
4560+ buf[i] = (char) path[i];
4561+ }
4562+ std::string lPath(buf);
4563+# else
4564+ std::string lPath(path);
4565+# endif
4566+ aPath = lPath.substr(0, lPath.rfind('\\'));
4567+ aPath += "\\cacert.pem";
4568+ if(GetFileAttributesA(aPath.c_str()) != INVALID_FILE_ATTRIBUTES)
4569+ curl_easy_setopt(lCurl, CURLOPT_CAINFO, aPath.c_str());
4570+ else
4571+ curl_easy_setopt(lCurl, CURLOPT_SSL_VERIFYPEER, 0L);
4572+}
4573+#endif //WIN32
4574+
4575+ class HttpSendFunction : public ContextualExternalFunction {
4576+ protected:
4577+ const ExternalModule* theModule;
4578+ ItemFactory* theFactory;
4579+
4580+ public:
4581+ HttpSendFunction(const ExternalModule* aModule)
4582+ : theModule(aModule),
4583+ theFactory(Zorba::getInstance(0)->getItemFactory()) {}
4584+
4585+ virtual ~HttpSendFunction() {}
4586+
4587+ public:
4588+ virtual String
4589+ getURI() const { return theModule->getURI(); }
4590+
4591+ virtual String
4592+ getLocalName() const { return "http-sequential-impl"; }
4593+
4594+ virtual ItemSequence_t
4595+ evaluate(const ExternalFunction::Arguments_t& args,
4596+ const StaticContext* aStaticContext, const DynamicContext* aDynamicContext)
4597+ const;
4598+ };
4599+
4600+ class HttpReadFunction : public HttpSendFunction {
4601+ public:
4602+ HttpReadFunction(const ExternalModule* aModule)
4603+ : HttpSendFunction(aModule) {}
4604+
4605+ virtual ~HttpReadFunction() {}
4606+
4607+ public:
4608+ virtual String
4609+ getLocalName() const { return "http-nondeterministic-impl"; }
4610+
4611+ };
4612+
4613+ class HttpClientModule : public ExternalModule {
4614+ protected:
4615+ class ltstr
4616+ {
4617+ public:
4618+ bool operator()(const String& s1, const String& s2) const
4619+ {
4620+ return s1.compare(s2) < 0;
4621+ }
4622+ };
4623+
4624+ typedef std::map<String, ExternalFunction*, ltstr> FuncMap_t;
4625+
4626+ FuncMap_t theFunctions;
4627+
4628+ public:
4629+ virtual ~HttpClientModule();
4630+
4631+ HttpClientModule() : theModuleUri("http://zorba.io/modules/http-client")
4632+ {
4633+ for (FuncMap_t::const_iterator lIter = theFunctions.begin();
4634+ lIter != theFunctions.end(); ++lIter) {
4635+ delete lIter->second;
4636+ }
4637+ theFunctions.clear();
4638+ }
4639+
4640+ virtual String
4641+ getURI() const { return theModuleUri; }
4642+
4643+ virtual ExternalFunction*
4644+ getExternalFunction(const String& aLocalname)
4645+ {
4646+ ExternalFunction*& lFunc = theFunctions[aLocalname];
4647+ if (!lFunc) {
4648+ if (aLocalname == "http-sequential-impl") {
4649+ lFunc = new HttpSendFunction(this);
4650+ } else if (aLocalname == "http-nondeterministic-impl") {
4651+ lFunc = new HttpReadFunction(this);
4652+ }
4653+ }
4654+ return lFunc;
4655+ }
4656+
4657+ virtual void
4658+ destroy()
4659+ {
4660+ if (!dynamic_cast<HttpClientModule*>(this)) {
4661+ return;
4662+ }
4663+ delete this;
4664+ }
4665+
4666+ private:
4667+ String theModuleUri;
4668+ };
4669+
4670+ ItemSequence_t
4671+ general_evaluate(
4672+ const ExternalFunction::Arguments_t& args,
4673+ const StaticContext* aStaticContext,
4674+ const DynamicContext* aDynamicContext,
4675+ ItemFactory* aFactory,
4676+ const String& aTheModuleURI)
4677+ {
4678+ CURL* lCURL = curl_easy_init();
4679+
4680+ Item lRequest;
4681+ Item lHref;
4682+ Item lContent;
4683+
4684+ Iterator_t arg0_iter = args[0]->getIterator();
4685+ arg0_iter->open();
4686+ bool lReqSet = arg0_iter->next(lRequest);
4687+ arg0_iter->close();
4688+
4689+ std::string lData;
4690+
4691+ std::auto_ptr<HttpRequestHandler> lHandler;
4692+ std::auto_ptr<RequestParser> lParser;
4693+ struct curl_slist* lHeaderList = 0;
4694+
4695+ ErrorThrower thrower(aFactory, &lHeaderList,aTheModuleURI);
4696+
4697+ if (lReqSet) {
4698+ lHandler.reset(new HttpRequestHandler(lCURL));
4699+ lParser.reset(new RequestParser(lHandler.get(), thrower, aFactory));
4700+ lParser->parseRequest(lRequest);
4701+ }
4702+ //curl_easy_setopt(lCURL, CURLOPT_USERAGENT, "libcurl-agent/1.0");
4703+ //curl_easy_setopt(lCURL, CURLOPT_PROXY, "localhost:8888");
4704+#ifdef WIN32
4705+ std::string caCertPath;
4706+ set_cacert(lCURL, caCertPath);
4707+#endif
4708+ HttpResponseHandler lRespHandler(aFactory, lHeaderList);
4709+ String lOverrideContentType;
4710+ if (lHandler.get())
4711+ lHandler->getOverrideContentType(lOverrideContentType);
4712+ bool lStatusOnly =
4713+ lHandler.get() == NULL ? false : (lHandler->isStatusOnly() || lHandler->isHeadRequest());
4714+ // This gives the ownership of lCurl to the HttpResponseParser
4715+ std::auto_ptr<HttpResponseParser> lRespParser(new HttpResponseParser(lRespHandler, lCURL, thrower,
4716+ lOverrideContentType.c_str(), lStatusOnly));
4717+ int lRetCode = lRespParser->parse();
4718+
4719+ if (lRetCode == CURLE_OPERATION_TIMEDOUT)
4720+ thrower.raiseException("TIMEOUT", "A timeout occurred waiting for the response");
4721+ else if (lRetCode)
4722+ {
4723+ thrower.raiseException("HTTP", "An HTTP error occurred");
4724+ }
4725+
4726+ // If the Parser is "self contained", that means it didn't create any
4727+ // objects with a lifecycle longer than itself; therefore we should free
4728+ // it (by letting auto_ptr delete it). If the Parser is not self contained,
4729+ // then it will have arranged for some other memory manager to free it
4730+ // later when appropriate; therefore we should NOT let auto_ptr delete it
4731+ // now.
4732+ if ( ! lRespParser->selfContained()) {
4733+ lRespParser.release();
4734+ }
4735+ return ItemSequence_t(lRespHandler.releaseResult());
4736+ }
4737+
4738+ ItemSequence_t
4739+ HttpSendFunction::evaluate(const ExternalFunction::Arguments_t& args,
4740+ const StaticContext* aStaticContext, const DynamicContext* aDynamicContext) const
4741+ {
4742+ return general_evaluate(args, aStaticContext, aDynamicContext, theFactory, getURI());
4743+ }
4744+
4745+ HttpClientModule::~HttpClientModule()
4746+ {
4747+ for (FuncMap_t::const_iterator lIter = theFunctions.begin();
4748+ lIter != theFunctions.end(); ++lIter) {
4749+ delete lIter->second;
4750+ }
4751+ theFunctions.clear();
4752+ }
4753+ } // namespace http_request
4754+} // namespace zorba
4755+
4756+#ifdef WIN32
4757+# define DLL_EXPORT __declspec(dllexport)
4758+#else
4759+# define DLL_EXPORT __attribute__ ((visibility("default")))
4760+#endif
4761+
4762+extern "C" DLL_EXPORT zorba::ExternalModule* createModule() {
4763+ return new zorba::http_client::HttpClientModule();
4764+}
4765+
4766
4767=== added file 'modules/http-client/json/http-client.xq.src/http_request_handler.cpp'
4768--- modules/http-client/json/http-client.xq.src/http_request_handler.cpp 1970-01-01 00:00:00 +0000
4769+++ modules/http-client/json/http-client.xq.src/http_request_handler.cpp 2013-07-25 09:33:27 +0000
4770@@ -0,0 +1,469 @@
4771+/*
4772+ * Copyright 2006-2013 The FLWOR Foundation.
4773+ *
4774+ * Licensed under the Apache License, Version 2.0 (the "License");
4775+ * you may not use this file except in compliance with the License.
4776+ * You may obtain a copy of the License at
4777+ *
4778+ * http://www.apache.org/licenses/LICENSE-2.0
4779+ *
4780+ * Unless required by applicable law or agreed to in writing, software
4781+ * distributed under the License is distributed on an "AS IS" BASIS,
4782+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4783+ * See the License for the specific language governing permissions and
4784+ * limitations under the License.
4785+ */
4786+
4787+#include <iostream>
4788+#include <cassert>
4789+
4790+#include <zorba/zorba.h>
4791+#include <zorba/singleton_item_sequence.h>
4792+#include <zorba/serializer.h>
4793+#include <zorba/api_shared_types.h>
4794+#include <zorba/xquery_functions.h>
4795+#include <zorba/zorba_functions.h>
4796+#include <zorba/util/base64_util.h>
4797+#include <zorba/util/base64_stream.h>
4798+#include <zorba/util/hexbinary_util.h>
4799+#include <zorba/util/hexbinary_stream.h>
4800+#include <zorba/xquery_functions.h>
4801+#include <zorba/util/transcode_stream.h>
4802+
4803+#include "http_request_handler.h"
4804+
4805+namespace zorba { namespace http_client {
4806+
4807+ HttpRequestHandler::HttpRequestHandler(CURL* aCurl)
4808+ : theCurl(aCurl),
4809+ theStatusOnly(false),
4810+ theInsideMultipart(false),
4811+ theLastBodyHadContent(false),
4812+ theSerStream(NULL),
4813+ thePost(NULL),
4814+ theLast(NULL),
4815+ theLastSerializerOptions(NULL),
4816+ thePostData(NULL),
4817+ theIsHeadRequest(false)
4818+ {
4819+ theHeaderLists.push_back(NULL);
4820+ }
4821+
4822+ HttpRequestHandler::~HttpRequestHandler()
4823+ {
4824+ std::vector<struct curl_slist*>::iterator lIter;
4825+ for (lIter = theHeaderLists.begin(); lIter != theHeaderLists.end(); ++lIter)
4826+ {
4827+ if (*lIter) {
4828+ curl_slist_free_all(*lIter);
4829+ }
4830+ }
4831+
4832+ if (thePost != NULL) {
4833+ curl_formfree(thePost);
4834+ }
4835+ delete theSerStream;
4836+ }
4837+
4838+ void HttpRequestHandler::begin()
4839+ {
4840+ }
4841+
4842+ void HttpRequestHandler::beginResponse(int aStatus, String aMessage)
4843+ {
4844+ }
4845+
4846+ void HttpRequestHandler::endResponse()
4847+ {
4848+ }
4849+
4850+ void HttpRequestHandler::beginRequest(String aMethod,
4851+ String href,
4852+ bool aStatusOnly,
4853+ String aUsername,
4854+ String aPassword,
4855+ String aAuthMethod,
4856+ bool aSendAuthorization,
4857+ String aOverrideContentType,
4858+ bool aFollowRedirect,
4859+ String aUserAgent,
4860+ int aTimeout /*= -1*/ )
4861+ {
4862+ aMethod = fn::upper_case(aMethod);
4863+ const char* lStr = aMethod.c_str();
4864+ theMethodString = lStr;
4865+ String const lAuthMethod = fn::lower_case(aAuthMethod);
4866+ if (theMethodString == "HEAD" || theMethodString == "OPTIONS") {
4867+ curl_easy_setopt(theCurl, CURLOPT_NOBODY, 1L);
4868+ theIsHeadRequest = true;
4869+ }
4870+ curl_easy_setopt(theCurl, CURLOPT_CUSTOMREQUEST, theMethodString.c_str());
4871+ if (href != "") {
4872+ curl_easy_setopt(theCurl, CURLOPT_URL, href.c_str());
4873+ }
4874+ if (aFollowRedirect) {
4875+ curl_easy_setopt(theCurl, CURLOPT_FOLLOWLOCATION, 1);
4876+ }
4877+ theStatusOnly = aStatusOnly;
4878+ theOverrideContentType = aOverrideContentType;
4879+ if (aTimeout != -1) {
4880+ curl_easy_setopt(theCurl, CURLOPT_TIMEOUT, aTimeout);
4881+ }
4882+ if (aUserAgent != "")
4883+ curl_easy_setopt( theCurl, CURLOPT_USERAGENT, aUserAgent.c_str() );
4884+ else
4885+ curl_easy_setopt( theCurl, CURLOPT_USERAGENT, "libcurl-agent/1.0" );
4886+
4887+ if (aUsername != "" && !aSendAuthorization) {
4888+ String lUserPw = aUsername + ":" + aPassword;
4889+ theUserPW = lUserPw.c_str();
4890+ curl_easy_setopt(theCurl, CURLOPT_USERPWD, theUserPW.c_str());
4891+ if (lAuthMethod == "basic") {
4892+ curl_easy_setopt(theCurl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
4893+ } else if (lAuthMethod == "digest") {
4894+ curl_easy_setopt(theCurl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
4895+ }
4896+ }
4897+ if (aUsername != "" && aSendAuthorization) {
4898+ if (lAuthMethod == "digest") {
4899+ String lUserPw = aUsername + ":" + aPassword;
4900+ theUserPW = lUserPw.c_str();
4901+ curl_easy_setopt(theCurl, CURLOPT_USERPWD, theUserPW.c_str());
4902+ curl_easy_setopt(theCurl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
4903+ } else {
4904+ String lAuthString = aUsername + ":" + aPassword;
4905+ String lAuth = "Authorization: ";
4906+ if (lAuthMethod == "basic")
4907+ {
4908+ lAuth += "Basic ";
4909+ }
4910+ else
4911+ {
4912+ lAuth += aAuthMethod + " ";
4913+ }
4914+ lAuth += zorba::base64::encode(lAuthString);
4915+ theAuthMethod = lAuth.c_str();
4916+ theHeaderLists[0] = curl_slist_append(theHeaderLists[0], theAuthMethod.c_str());
4917+ }
4918+ }
4919+ }
4920+
4921+ void HttpRequestHandler::endRequest()
4922+ {
4923+ }
4924+
4925+ void HttpRequestHandler::header(String aName, String aValue)
4926+ {
4927+ std::string lValue = aName.c_str();
4928+ lValue += ":";
4929+ lValue += aValue.c_str();
4930+ theHeaderStrings.push_back(lValue);
4931+ if (!theInsideMultipart) {
4932+ theHeaderLists[0] = curl_slist_append(theHeaderLists[0], lValue.c_str());
4933+ } else {
4934+ if (aName == "Content-Disposition") {
4935+ Sequence<String> lTokens(fn::tokenize(aValue, ";"));
4936+ for (String lNextToken; lTokens.next( &lNextToken );) {
4937+ std::pair<String, String> lKeyValue = twinSplit(lNextToken);
4938+ if (lKeyValue.first == "name") {
4939+ theMultipartName = lKeyValue.second;
4940+ zfn::trim(theMultipartName, "\"\'");
4941+ }
4942+ else if (lKeyValue.first == "filename") {
4943+ theMultiPartFileName = lKeyValue.second;
4944+ zfn::trim(theMultiPartFileName, "\"\'");
4945+ }
4946+ }
4947+ } else {
4948+ theHeaderLists.back() = curl_slist_append(theHeaderLists.back(), (lValue).c_str());
4949+ }
4950+ }
4951+ }
4952+
4953+ void HttpRequestHandler::beginBody(String aContentType,
4954+ String aSrc,
4955+ ItemSequence* aSerializerOptions)
4956+ {
4957+ theLastSerializerOptions = aSerializerOptions;
4958+ theSerStream = new std::ostringstream();
4959+ theCurrentContentType = aContentType;
4960+ theContentType = "Content-Type: ";
4961+ theContentType += aContentType.c_str();
4962+ if (!theInsideMultipart) {
4963+ theHeaderLists[0] = curl_slist_append(theHeaderLists[0], theContentType.c_str());
4964+ } else {
4965+ theHeaderLists.back() = curl_slist_append(theHeaderLists.back(), theContentType.c_str());
4966+ }
4967+ }
4968+ void HttpRequestHandler::any(Item aItem, std::string& charset)
4969+ {
4970+ theLastBodyHadContent = true;
4971+ bool lTranscoderAttached = false;
4972+
4973+ switch (aItem.getTypeCode())
4974+ {
4975+ case store::XS_STRING:
4976+ if (!charset.empty() && transcode::is_necessary(charset.c_str()))
4977+ {
4978+ transcode::attach(*theSerStream,charset.c_str());
4979+ lTranscoderAttached = true;
4980+ }
4981+
4982+ try
4983+ {
4984+ if (aItem.isStreamable())
4985+ emitStreamableString(aItem);
4986+ else
4987+ emitString(aItem);
4988+ }
4989+ catch ( ... )
4990+ {
4991+ if (lTranscoderAttached)
4992+ transcode::detach(*theSerStream);
4993+ }
4994+
4995+ if (lTranscoderAttached)
4996+ transcode::detach(*theSerStream);
4997+ break;
4998+ case store::XS_BASE64BINARY:
4999+ if (aItem.isStreamable())
5000+ emitStreamableBase64Binary(aItem);
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches