This document is also available in these non-normative formats: XML.
This proposal provides an HTTP client interface for XPath 2.0. It defines one extension function to perform HTTP requests, and has been designed to be compatible with XQuery 1.0 and XSLT 2.0, as well as any other XPath 2.0 usage.
1 Introduction
1.1 Namespace conventions
1.2 Error management
2 The http:send-request function
3 Sending a request
3.1 The request elements
3.2 Serializing the request content
3.3 Authentication
4 Dealing with the response
4.1 The result element
4.2 Representing the result content
5 Content types handling
TODO: Add @href to http:response, taking redirects into account.
TODO: Do not we want 'hex' and 'base64' serialization methods instead of 'binary'? (or in addition to?)
The module defined by this document does define one function in the namespace
http://expath.org/ns/http-client. In this document, the
http prefix, when used, is bound to this namespace URI.
Error codes are defined in the namespace http://expath.org/ns/error. In
this document, the err prefix, when used, is bound to this namespace
URI.
Error conditions are identified by a code (a QName). When such an error
condition is reached during the execution of the function, a dynamic error is thrown,
with the corresponding error code (as if the standard XPath function
error had been called).
Error codes are defined through the spec. For too many reasons to enumerate here, the HTTP protocol layer can raise an error. In this case, if the error condition is not mentioned explicitly in the spec, the implementation must raise an error with an appropriate message [err:HC001].
http:send-request functionThis module defines an XPath extension function that sends an HTTP request and return the corresponding response. It supports HTTP multi-part messages. Here is the signature of this function:
http:send-request($request aselement(http:request)?, $href asxs:string?, $bodies asitem()*) asitem()+
$request contains the various parameters of the request, for instance
the HTTP method to use or the HTTP headers. Among other things, it can also
contain the other param's values: the URI and the bodies. If they are not set as
parameter to the function, their value in $request, if any, is used instead. See
the following section for the detailed definition of the http:request element. If
the parameter does not follow the grammar defined in this spec, this is an error
[err:HC005].
$href is the HTTP or HTTPS URI to send the request to. It is an
xs:anyURI, but is declared as a string to be able to pass literal strings (without
requiring to explicitly cast it to an xs:anyURI).
$bodies is the request body content, for HTTP methods that can
contain a body in the request (e.g. POST). This is an error if this param is not
the empty sequence for methods that must be empty (e.g. DELETE). The details of
the methods are defined in their respective specs (e.g. [RFC 2616] or
[RFC 4918]). In case of a multipart request, it can be a sequence
of several items, each one is the body of the corresponding body descriptor in
$request. See below for details.
Besides the 3-params signature above, there are 2 other signatures that are convenient shortcuts (corresponding to the full version in which corresponding params have been set to the empty sequence). They are:
http:send-request($request aselement(http:request)) asitem()+http:send-request($request aselement(http:request)?, $href asxs:string?) asitem()+
The functions defined in this module make one able to send a request to an HTTP server and receive the corresponding response. Here is how the request is represented by the parameters to this function, and how they are used to generate the actual HTTP request to send.
The http:request element represents all the needed
information to send the HTTP request. So it is always possible
to create such an element that will carry over all the needed info
for a particular request. For some of those values though, you
can use an additional param instead. For instance, some signatures
define the parameter $href. If the value of this parameter
is not the empty sequence, it will then be used instead of the value
of the attribute href on the http:request
element.
<http:request method = ncname
href? = uri
status-only? = boolean
username? = string
password? = string
auth-method? = string
send-authorization? = boolean
override-media-type? = string
follow-redirect? = boolean
timeout? = integer>
(http:header*,
(http:multipart|
http:body)?)
</http:request>
method is the HTTP verb to use, as GET, POST, etc. It is case
insensitive
href is the URI the request has to be sent to. It can be overridden
by the parameter $href
status-only control how the response will look like; if it is
true, only the status code and the headers are returned, the content is not
(no http:body nor http:multipart, nor the interpreted additional value in the
returned sequence, see hereafter).
username, password, auth-method
and send-authorization are used for authentication (see section
below).
override-media-type is a MIME type. It can be used only with
http:request, and will override the Content-Type header returned
by the server.
follow-redirect control whether an HTTP redirect is automatically
followed or not. If it is false, the HTTP redirect is returned as the response.
If it is true (the default) the function tries to follow the redirect, by sending
the same request to the new address (including body, headers, and authentication
credentials). Maximum one redirect is followed (there is no attempt to follow
a redirect in response to following a first redirect).
timeout is the maximum number of seconds to wait for the server to
respond. If this time duration is reached, an error is thrown [err:HC006]. (TODO: Allow one to ask for an empty sequence
instead?)
http:header represent an HTTP header, either in the
http:request or in the http:response elements, as
defined below.
http:multipart represents a multi-part body, either in a request
or a response, as defined below.
http:body represents the body, either of a request or a response,
as defined below.
The http:header element represents an HTTP header, either in a request
or in a response:
<http:header name = string
value = string>
empty
</http:header>The http:body element represents the body of either an HTTP request or
of an HTTP response (in multipart requests and responses, it represents the body of a
single one part):
<http:body media-type = string
src? = uri
method? = "xml" | "html" | "xhtml" | "text" | "binary"
| qname-but-not-ncname
byte-order-mark? = "yes" | "no"
cdata-section-elements? = qnames
doctype-public? = string
doctype-system? = string
encoding? = string
escape-uri-attributes? = "yes" | "no"
indent? = "yes" | "no"
normalization-form? = "NFC" | "NFD" | "NFKC" | "NFKD"
| "fully-normalized" | "none" | nmtoken
omit-xml-declaration? = "yes" | "no"
standalone? = "yes" | "no" | "omit"
suppress-indentation? = qnames
undeclare-prefixes? = "yes" | "no"
output-version? = nmtoken>
any*
</http:body>The media-type is the MIME media type of the body part. It is mandatory.
In a request it is given by the user and is the default value of the Content-Type
header if it is not set explicitly. In a response, it is given by the implementation
from the Content-Type header returned by the server. The src attribute
can be used in a request to set the body content as the content of the linked
resource instead of using the children of the http:body element. When
this attribute is used, only the media-type attribute must also be
present, and there can be neither content in the http:body element, nor
any other attribute, or this is an error [err:HC004].
All the attributes, except src, are used to set the corresponding
serialization parameter defined in [Serialization], as defined for the XPath
2.1 function fn:serialize()
[F&O 1.1]. A difference here is that the serialization parameter
include-content-type does not make sense, so it is not available on
the http:body element (its value is always "yes"). Those attributes can
be given by the user on a request to control the way a part body is serialized. In
the response, the implementation can, but is not required, to provide some of them if
it has the corresponding information (some of them do not make any sense in a
response, therefore they will never be on a response element, for instance
output-version).
The http:multipart element represents an HTTP multi-part request or
response:
<http:multipart media-type = string
boundary? = string>
(http:header*,
http:body)+
</http:multipart>The media-type attribute is the media type of the whole request or
response, and has to be a multipart media type (that is, its main type must be
multipart). The boundary attribute is the boundary
marker used to separate the several parts in the message (the value of the attribute
is prefixed with "--" to form the actual boundary marker in the request;
on the other way, this prefix is removed from the boundary marker in the response to
set the value of the attribute).
If the request can have content (one body or several body parts), it can be specified
by the http:multipart element, the http:body element,
and/or the parameter $bodies. For each body, the content of the HTTP
body is generated as follow.
Except when its attribute src is present, a http:request
element can have several attributes representing serialization parameters, as defined
in [Serialization]. This spec defines in addition the method
'binary'; in this case the body content must be either an
xs:hexBinary or an xs:base64Binary item, and no other serialization parameter can be
set besides media-type.
The default value of the serialization method depends on the media-type:
it is 'xml' if it is an XML media type, 'html' if it is an
HTML media type, 'xhtml' if it is application/xhtml+xml,
'text' if it is a textual media type, and 'binary' for
any other case.
When a body element has an empty content (i.e. it has no child node at all) its
content is given by the parameter $bodies. In a single part request,
this param must have at most one item. If the body is empty, the param cannot be the
empty sequence. In a multipart request, $bodies must have as many items
as there are empty body elements. If there are three empty body elements, the content
of the first of them is $bodies[1], and so on. The number of empty body
elements must be equal to the number of items in $bodies.
HTTP authentication when sending a request is controlled by the attributes
username, password, auth-method and
send-authorization on the element http:request.
If username has a value, password and
auth-method must have a value too. And if any one of the three
other attributes have been set, username must be set too.
The attribute auth-method can be either "Basic" or
"Digest", but other values can also be used, in an
implementation-defined way. The handling of those attributes must be done
in conformance to [RFC 2617]. If send-authorization
is true (default value is false) and the authentication method supports
generating the header Authorization without challenge, the
request contains this header. The default value is to send a non-authenticated
request, and if the response is an authentication challenge, then only send
the credentials in a second message.
After having sent the request to the HTTP server, the function waits for
the response. It analyses it and returns a sequence representing this
response. This sequence has an http:response element as
first item, which is followed be an additional item for each body or
body part in the response.
<http:response status = integer
message = string>
(http:header*,
(http:multipart |
http:body)?)
</http:response>
This is the first item returned by the function defined in this module.
The status attribute is the HTTP status code returned by the
server, and message is the message coming with the status on the
status line. The http:header elements are as defined for the
request, but represent instead the response headers. The http:body
and http:multipart elements are also like in the request, but
http:body elements must be empty.
Instead of being inserted within the http:response element, the
content of each body is returned as a single item in the return sequence.
Each item is in the same order (after the http:response element)
than the http:body elements. For each body, the way this item
is built from the HTTP response is as follow.
If the status-only attribute has the value true
(default is false), the returned sequence will only contain the
http:response element (with the headers, but also the empty
http:body or http:multipart elements, as if
status-only was false), and the following items, representing
the bodies content are not generated from the HTTP response.
For each body that has to be interpreted, the following rules apply in order to build the corresponding item. If the body media type is a text media type, the item is a string, containing the body content. If the media type is an XML media type, the content is parsed and the item is the resulting document node. If the media type is an HTML type, the content is tidied up and parsed (this process is implementation-dependant) and the item is the resulting document node. If this is a binary media type, the content is returned as a base64Binary item. From the previous rules, a result item can then be either a document node (from XML or HTML), a string or a base64Binary.
When the type of a part is either XML or HTML, its body has to be parsed into a document node. If there is any error when parsing the content, an error is raised with an appropriate message [err:HC002].
If the attribute override-media-type is set on the request, its value is
used instead of the Content-Type returned by the HTTP server. If the Content-Type of
the response is a multipart type, the value of override-media-type can
only be a multipart type, or application/octet-stream (to get the raw
entity as a binary item). If it is not, this is an error [err:HC003].
In both requests and responses, MIME type strings are used to choose the way the entity content has to be respectively serialized or parsed. Four different kinds of type are defined here, which are used in the above text about sending request and receiving response. The intent is to provide the spirit of the entity content handling regarding its content type, but an implementation is encouraged to deviate from those rules if it is obvious that a particular type should be treated in a specific way (normally, that would be the case only to treat a binary type as another type).
An XML media type has a MIME type of text/xml,
application/xml, text/xml-external-parsed-entity,
or application/xml-external-parsed-entity, as defined in
[RFC 3023] (except that application/xml-dtd is
considered a text media type). MIME types ending by +xml are
also XML media types.
An HTML media type has a MIME type of text/html.
Text media types are the remaining types beginning with text/.
Binary types are all the other types. An implementation can treat some of those binary types as either an XML, HTML or text media type if it is more appropriate (this is implementation-defined).
The structure of most of the elements and most of the attributes used in this candidate are inspired from the corresponding step in [XProc].