Search in sources :

Example 6 with XmlParseException

use of com.zimbra.common.soap.XmlParseException in project zm-mailbox by Zimbra.

the class DavServlet method isProxyRequest.

private boolean isProxyRequest(DavContext ctxt, DavMethod m) throws IOException, DavException, ServiceException {
    Provisioning prov = Provisioning.getInstance();
    ItemId target = null;
    String extraPath = null;
    String requestPath = ctxt.getPath();
    try {
        if (ctxt.getUser() == null) {
            return false;
        }
        if (requestPath == null || requestPath.length() < 2) {
            return false;
        }
        Account account = prov.getAccountByName(ctxt.getUser());
        if (account == null) {
            return false;
        }
        Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account);
        Pair<Folder, String> match = mbox.getFolderByPathLongestMatch(ctxt.getOperationContext(), Mailbox.ID_FOLDER_USER_ROOT, requestPath);
        Folder targetFolder = match.getFirst();
        if (!(targetFolder instanceof Mountpoint)) {
            return false;
        }
        Mountpoint mp = (Mountpoint) targetFolder;
        target = new ItemId(mp.getOwnerId(), mp.getRemoteId());
        extraPath = match.getSecond();
    } catch (ServiceException e) {
        ZimbraLog.dav.debug("can't get path", e);
        return false;
    }
    // we also don't proxy DELETE on a mountpoint.
    if (extraPath == null && (m.getName().equals(PropFind.PROPFIND) && ctxt.getDepth() == DavContext.Depth.zero || m.getName().equals(PropPatch.PROPPATCH) || m.getName().equals(Delete.DELETE))) {
        return false;
    }
    String prefix = ctxt.getPath();
    if (extraPath != null) {
        prefix = prefix.substring(0, prefix.indexOf(extraPath));
    }
    prefix = HttpUtil.urlEscape(DAV_PATH + "/" + ctxt.getUser() + prefix);
    if (!prefix.endsWith("/")) {
        prefix += "/";
    }
    // make sure the target account exists.
    Account acct = prov.getAccountById(target.getAccountId());
    if (acct == null) {
        return false;
    }
    Server server = prov.getServer(acct);
    if (server == null) {
        return false;
    }
    // get the path to the target mail item
    AuthToken authToken = AuthProvider.getAuthToken(ctxt.getAuthAccount());
    ZMailbox.Options zoptions = new ZMailbox.Options(authToken.toZAuthToken(), AccountUtil.getSoapUri(acct));
    zoptions.setNoSession(true);
    zoptions.setTargetAccount(target.getAccountId());
    zoptions.setTargetAccountBy(Key.AccountBy.id);
    ZMailbox zmbx = ZMailbox.getMailbox(zoptions);
    ZFolder f = zmbx.getFolderById("" + target.toString());
    if (f == null) {
        return false;
    }
    String path = f.getPath();
    String newPrefix = HttpUtil.urlEscape(DAV_PATH + "/" + acct.getName() + f.getPath());
    if (ctxt.hasRequestMessage()) {
        // replace the path in <href> of the request with the path to the target mail item.
        Document req = ctxt.getRequestMessage();
        for (Object hrefObj : req.getRootElement().elements(DavElements.E_HREF)) {
            if (!(hrefObj instanceof Element)) {
                continue;
            }
            Element href = (Element) hrefObj;
            String v = href.getText();
            // prefix matching is not as straightforward as we have jetty redirect from /dav to /home/dav.
            href.setText(newPrefix + "/" + v.substring(v.lastIndexOf('/') + 1));
        }
    }
    // build proxy request
    String url = getProxyUrl(ctxt.getRequest(), server, DAV_PATH) + HttpUtil.urlEscape("/" + acct.getName() + path + "/" + (extraPath == null ? "" : extraPath));
    HttpState state = new HttpState();
    authToken.encode(state, false, server.getAttr(Provisioning.A_zimbraServiceHostname));
    HttpClient client = ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
    client.setState(state);
    HttpMethod method = m.toHttpMethod(ctxt, url);
    method.setRequestHeader(new Header(DavProtocol.HEADER_USER_AGENT, "Zimbra-DAV/" + BuildInfo.VERSION));
    if (ZimbraLog.dav.isDebugEnabled()) {
        Enumeration<String> headers = ctxt.getRequest().getHeaderNames();
        while (headers.hasMoreElements()) {
            String hdr = headers.nextElement();
            if (!PROXY_REQUEST_HEADERS.contains(hdr) && !IGNORABLE_PROXY_REQUEST_HEADERS.contains(hdr)) {
                ZimbraLog.dav.debug("Dropping header(s) with name [%s] from proxy request (not in PROXY_REQUEST_HEADERS)", hdr);
            }
        }
    }
    for (String h : PROXY_REQUEST_HEADERS) {
        String hval = ctxt.getRequest().getHeader(h);
        if (hval != null) {
            method.addRequestHeader(h, hval);
        }
    }
    int statusCode = HttpClientUtil.executeMethod(client, method);
    if (ZimbraLog.dav.isDebugEnabled()) {
        for (Header hval : method.getResponseHeaders()) {
            String hdrName = hval.getName();
            if (!PROXY_RESPONSE_HEADERS.contains(hdrName) && !IGNORABLE_PROXY_RESPONSE_HEADERS.contains(hdrName)) {
                ZimbraLog.dav.debug("Dropping header [%s] from proxy response (not in PROXY_RESPONSE_HEADERS)", hval);
            }
        }
    }
    for (String h : PROXY_RESPONSE_HEADERS) {
        for (Header hval : method.getResponseHeaders(h)) {
            String hdrValue = hval.getValue();
            if (DavProtocol.HEADER_LOCATION.equals(h)) {
                int pfxLastSlashPos = prefix.lastIndexOf('/');
                int lastSlashPos = hdrValue.lastIndexOf('/');
                if ((lastSlashPos > 0) && (pfxLastSlashPos > 0)) {
                    hdrValue = prefix.substring(0, pfxLastSlashPos) + hdrValue.substring(lastSlashPos);
                    ZimbraLog.dav.debug("Original [%s] from proxy response new value '%s'", hval, hdrValue);
                }
            }
            ctxt.getResponse().addHeader(h, hdrValue);
        }
    }
    ctxt.getResponse().setStatus(statusCode);
    ctxt.setStatus(statusCode);
    try (InputStream in = method.getResponseBodyAsStream()) {
        switch(statusCode) {
            case DavProtocol.STATUS_MULTI_STATUS:
                // rewrite the <href> element in the response to point to local mountpoint.
                try {
                    Document response = W3cDomUtil.parseXMLToDom4jDocUsingSecureProcessing(in);
                    Element top = response.getRootElement();
                    for (Object responseObj : top.elements(DavElements.E_RESPONSE)) {
                        if (!(responseObj instanceof Element)) {
                            continue;
                        }
                        Element href = ((Element) responseObj).element(DavElements.E_HREF);
                        String v = href.getText();
                        v = URLDecoder.decode(v);
                        // Bug:106438, because v contains URL encoded value(%40) for '@' the comparison fails
                        if (v.startsWith(newPrefix)) {
                            href.setText(prefix + v.substring(newPrefix.length() + 1));
                        }
                    }
                    if (ZimbraLog.dav.isDebugEnabled()) {
                        ZimbraLog.dav.debug("PROXY RESPONSE:\n%s", new String(DomUtil.getBytes(response), "UTF-8"));
                    }
                    DomUtil.writeDocumentToStream(response, ctxt.getResponse().getOutputStream());
                    ctxt.responseSent();
                } catch (XmlParseException e) {
                    ZimbraLog.dav.warn("proxy request failed", e);
                    return false;
                }
                break;
            default:
                if (in != null) {
                    ByteUtil.copy(in, true, ctxt.getResponse().getOutputStream(), false);
                }
                ctxt.responseSent();
                break;
        }
        return true;
    }
}
Also used : Account(com.zimbra.cs.account.Account) Options(com.zimbra.cs.dav.service.method.Options) Server(com.zimbra.cs.account.Server) Element(org.dom4j.Element) HttpState(org.apache.commons.httpclient.HttpState) Folder(com.zimbra.cs.mailbox.Folder) ZFolder(com.zimbra.client.ZFolder) Document(org.dom4j.Document) ItemId(com.zimbra.cs.service.util.ItemId) Provisioning(com.zimbra.cs.account.Provisioning) ZMailbox(com.zimbra.client.ZMailbox) Mailbox(com.zimbra.cs.mailbox.Mailbox) ZMailbox(com.zimbra.client.ZMailbox) ZFolder(com.zimbra.client.ZFolder) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) GZIPInputStream(java.util.zip.GZIPInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) XmlParseException(com.zimbra.common.soap.XmlParseException) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) Header(org.apache.commons.httpclient.Header) HttpClient(org.apache.commons.httpclient.HttpClient) AuthToken(com.zimbra.cs.account.AuthToken) HttpMethod(org.apache.commons.httpclient.HttpMethod)

Aggregations

XmlParseException (com.zimbra.common.soap.XmlParseException)6 Element (com.zimbra.common.soap.Element)4 HttpMethod (org.apache.commons.httpclient.HttpMethod)3 ByteArrayInputStream (java.io.ByteArrayInputStream)2 InputStream (java.io.InputStream)2 ArrayList (java.util.ArrayList)2 Header (org.apache.commons.httpclient.Header)2 Document (org.dom4j.Document)2 Element (org.dom4j.Element)2 ZFolder (com.zimbra.client.ZFolder)1 ZMailbox (com.zimbra.client.ZMailbox)1 ServiceException (com.zimbra.common.service.ServiceException)1 XMLElement (com.zimbra.common.soap.Element.XMLElement)1 SoapParseException (com.zimbra.common.soap.SoapParseException)1 SoapProtocol (com.zimbra.common.soap.SoapProtocol)1 Account (com.zimbra.cs.account.Account)1 AuthToken (com.zimbra.cs.account.AuthToken)1 Config (com.zimbra.cs.account.Config)1 Cos (com.zimbra.cs.account.Cos)1 Provisioning (com.zimbra.cs.account.Provisioning)1