}
public void run() throws SaxonApiException {
super.run();
XdmNode requestDoc = source.read();
XdmNode start = S9apiUtils.getDocumentElement(requestDoc);
if (!c_request.equals(start.getNodeName())) {
throw XProcException.stepError(40);
}
// Check for valid attributes
XdmSequenceIterator iter = start.axisIterator(Axis.ATTRIBUTE);
boolean ok = true;
while (iter.hasNext()) {
XdmNode attr = (XdmNode) iter.next();
QName name = attr.getNodeName();
if (_method.equals(name) || _href.equals(name) || _detailed.equals(name)
|| _status_only.equals(name) || _username.equals(name) || _password.equals(name)
|| _auth_method.equals(name) || _send_authorization.equals(name)
|| _override_content_type.equals(name)) {
// nop
} else {
if (XMLConstants.DEFAULT_NS_PREFIX.equals(name.getNamespaceURI())) {
throw new XProcException(step.getNode(), "Unsupported attribute on c:request for p:http-request: " + name);
}
}
}
String send = step.getExtensionAttribute(cx_send_binary);
encodeBinary = !"true".equals(send);
method = start.getAttributeValue(_method);
statusOnly = "true".equals(start.getAttributeValue(_status_only));
detailed = "true".equals(start.getAttributeValue(_detailed));
overrideContentType = start.getAttributeValue(_override_content_type);
if (method == null) {
throw XProcException.stepError(6);
}
if (statusOnly && !detailed) {
throw XProcException.stepError(4);
}
if (start.getAttributeValue(_href) == null) {
throw new XProcException(step.getNode(), "The 'href' attribute must be specified on c:request for p:http-request");
}
requestURI = start.getBaseURI().resolve(start.getAttributeValue(_href));
String scheme = requestURI.getScheme();
if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) {
doFile(start.getAttributeValue(_href), start.getBaseURI().toASCIIString());
return;
}
HttpParams params = new BasicHttpParams();
HttpContext localContext = new BasicHttpContext();
// The p:http-request step should follow redirect requests if they are returned by the server.
params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, true);
// What about cookies
String saveCookieKey = step.getExtensionAttribute(cx_save_cookies);
String useCookieKeys = step.getExtensionAttribute(cx_use_cookies);
String cookieKey = step.getExtensionAttribute(cx_cookies);
if (saveCookieKey == null) {
saveCookieKey = cookieKey;
}
if (useCookieKeys == null) {
useCookieKeys = cookieKey;
}
// If a redirect response includes cookies, those cookies should be forwarded
// as appropriate to the redirected location when the redirection is followed.
CookieStore cookieStore = new BasicCookieStore();
if (useCookieKeys != null && useCookieKeys.equals(saveCookieKey)) {
cookieStore = runtime.getCookieStore(useCookieKeys);
} else if (useCookieKeys != null) {
CookieStore useCookieStore = runtime.getCookieStore(useCookieKeys);
for (Cookie cookie : useCookieStore.getCookies()) {
cookieStore.addCookie(cookie);
}
}
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
// FIXME: Is browser compatability the right thing? It's the right thing for my unit test...
params.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
String timeOutStr = step.getExtensionAttribute(cx_timeout);
if (timeOutStr != null) {
params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, Integer.parseInt(timeOutStr));
}
if (start.getAttributeValue(_username) != null) {
String user = start.getAttributeValue(_username);
String pass = start.getAttributeValue(_password);
String meth = start.getAttributeValue(_auth_method);
List<String> authpref;
if ("basic".equalsIgnoreCase(meth)) {
authpref = Collections.singletonList(AuthPolicy.BASIC);
} else if ("digest".equalsIgnoreCase(meth)) {
authpref = Collections.singletonList(AuthPolicy.DIGEST);
} else {
throw XProcException.stepError(3, "Unsupported auth-method: " + meth);
}
String host = requestURI.getHost();
int port = requestURI.getPort();
AuthScope scope = new AuthScope(host,port);
UsernamePasswordCredentials cred = new UsernamePasswordCredentials(user, pass);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(scope, cred);
localContext.setAttribute(ClientContext.CREDS_PROVIDER, credsProvider);
params.setBooleanParameter(ClientPNames.HANDLE_AUTHENTICATION, true);
params.setParameter(AuthPNames.TARGET_AUTH_PREF, authpref);
}
iter = start.axisIterator(Axis.CHILD);
XdmNode body = null;
while (iter.hasNext()) {
XdmNode event = (XdmNode) iter.next();
// FIXME: What about non-whitespace text nodes?
if (event.getNodeKind() == XdmNodeKind.ELEMENT) {
if (body != null) {
throw new UnsupportedOperationException("Elements follow c:multipart or c:body");
}
if (XProcConstants.c_header.equals(event.getNodeName())) {
String name = event.getAttributeValue(_name);
if (name == null) {
continue; // this can't happen, right?
}
if (name.toLowerCase().equals("content-type")) {
// We'll deal with the content-type header later
headerContentType = event.getAttributeValue(_value).toLowerCase();
} else {
headers.add(new BasicHeader(event.getAttributeValue(_name), event.getAttributeValue(_value)));
}
} else if (XProcConstants.c_multipart.equals(event.getNodeName())
|| XProcConstants.c_body.equals(event.getNodeName())) {
body = event;
} else {
throw new UnsupportedOperationException("Unexpected request element: " + event.getNodeName());
}
}
}
String lcMethod = method.toLowerCase();
// You can only have a body on PUT or POST
if (body != null && !("put".equals(lcMethod) || "post".equals(lcMethod))) {
throw XProcException.stepError(5);
}
HttpUriRequest httpRequest;
HttpResponse httpResult = null;
if ("get".equals(lcMethod)) {
httpRequest = doGet();
} else if ("post".equals(lcMethod)) {
httpRequest = doPost(body);
} else if ("put".equals(lcMethod)) {
httpRequest = doPut(body);
} else if ("head".equals(lcMethod)) {
httpRequest = doHead();
} else if ("delete".equals(lcMethod)) {
httpRequest = doDelete();
} else {
throw new UnsupportedOperationException("Unrecognized http method: " + method);
}
TreeWriter tree = new TreeWriter(runtime);
try {
// Execute the method.
HttpClient httpClient = runtime.getHttpClient();
if (httpClient == null) {
throw new XProcException("HTTP requests have been disabled");
}
httpRequest.setParams(params);
httpResult = httpClient.execute(httpRequest, localContext);
int statusCode = httpResult.getStatusLine().getStatusCode();
HttpHost host = (HttpHost) localContext.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
HttpUriRequest req = (HttpUriRequest) localContext.getAttribute(ExecutionContext.HTTP_REQUEST);
URI root = new URI(host.getSchemeName(), null, host.getHostName(), host.getPort(), "/", null, null);
tree.startDocument(root.resolve(req.getURI()));
// Deal with cookies
if (saveCookieKey != null) {
runtime.setCookieStore(saveCookieKey, cookieStore);
}
String contentType = getContentType(httpResult);
if (overrideContentType != null) {
if ((xmlContentType(contentType) && overrideContentType.startsWith("image/"))
|| (contentType.startsWith("text/") && overrideContentType.startsWith("image/"))
|| (contentType.startsWith("image/") && xmlContentType(overrideContentType))
|| (contentType.startsWith("image/") && overrideContentType.startsWith("text/"))
|| (contentType.startsWith("multipart/") && !overrideContentType.startsWith("multipart/"))
|| (!contentType.startsWith("multipart/") && overrideContentType.startsWith("multipart/"))) {
throw XProcException.stepError(30);
}
//System.err.println(overrideContentType + " overrides " + contentType);
contentType = overrideContentType;
}
if (detailed) {
tree.addStartElement(XProcConstants.c_response);
tree.addAttribute(_status, "" + statusCode);
tree.startContent();
for (Header header : httpResult.getAllHeaders()) {
// I don't understand why/how HeaderElement parsing works. I get very weird results.
// So I'm just going to go the long way around...
String h = header.toString();
int cp = h.indexOf(":");
String name = header.getName();
String value = h.substring(cp+1).trim();
tree.addStartElement(XProcConstants.c_header);
tree.addAttribute(_name, name);
tree.addAttribute(_value, value);
tree.startContent();
tree.addEndElement();
}
if (statusOnly) {
// Skip reading the result
} else if (httpResult.getEntity() != null) {
// Read the response body.
InputStream bodyStream = httpResult.getEntity().getContent();
if (bodyStream != null) {
readBodyContent(tree, bodyStream, httpResult);
}
}
tree.addEndElement();
} else {
if (statusOnly) {
// Skip reading the result
} else {
// Read the response body.
if (httpResult.getEntity() != null) {
InputStream bodyStream = httpResult.getEntity().getContent();
readBodyContent(tree, bodyStream, httpResult);
} else {
throw XProcException.dynamicError(6);
}
}
}
} catch (XProcException e) {
throw e;
} catch (Exception e) {
throw new XProcException(e);
} finally {
// Release the connection.
if (httpResult != null) {
EntityUtils.consumeQuietly(httpResult.getEntity());
}
}
tree.endDocument();
XdmNode resultNode = tree.getResult();
result.write(resultNode);
}