/*
 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     bstefanescu
 *     ataillefer
 */
package org.nuxeo.ecm.automation.client.jaxrs.impl;

import java.io.UnsupportedEncodingException;
import java.util.Map;

import javax.mail.internet.MimeMultipart;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.nuxeo.ecm.automation.client.RemoteException;
import org.nuxeo.ecm.automation.client.jaxrs.spi.Connector;
import org.nuxeo.ecm.automation.client.jaxrs.spi.Request;

/**
 * Connector wrapping a {@link HttpClient} instance.
 *
 *
 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
 * @author <a href="mailto:ataillefer@nuxeo.com">Antoine Taillefer</a>
 */
public class HttpConnector implements Connector {

    protected final HttpClient http;

    /**
     * Timeout in milliseconds for the socket, connection manager and connection
     * used by {@link #http}.
     */
    protected final int httpConnectionTimeout;

    protected final HttpContext ctx;

    protected String basicAuth;

    public HttpConnector(HttpClient http) {
        this(http, 0);
    }

    /**
     * Allows to set a timeout for the HTTP connection to avoid infinite or
     * quite long waiting periods if:
     * <ul>
     * <li>Nuxeo is broken or running into an infinite loop</li>
     * <li>the network doesn't respond at all</li>
     * </ul>
     *
     * @since 5.7
     */
    public HttpConnector(HttpClient http, int httpConnectionTimeout) {
        this(http, new BasicHttpContext(), httpConnectionTimeout);
    }

    public HttpConnector(HttpClient http, HttpContext ctx) {
        this(http, ctx, 0);
    }

    /**
     * @see #HttpConnector(HttpClient, long)
     * @since 5.7
     */
    public HttpConnector(HttpClient http, HttpContext ctx,
            int httpConnectionTimeout) {
        ctx.setAttribute(ClientContext.COOKIE_STORE, new BasicCookieStore());
        this.http = http;
        this.httpConnectionTimeout = httpConnectionTimeout;
        this.ctx = ctx;
    }

    @Override
    public Object execute(Request request) {
        HttpRequestBase httpRequest = null;
        if (request.getMethod() == Request.POST) {
            HttpPost post = new HttpPost(request.getUrl());
            Object obj = request.getEntity();
            if (obj != null) {
                HttpEntity entity = null;
                if (request.isMultiPart()) {
                    entity = new MultipartRequestEntity((MimeMultipart) obj);
                } else {
                    try {
                        entity = new StringEntity(obj.toString(), "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        throw new Error("Cannot encode into UTF-8", e);
                    }
                }
                post.setEntity(entity);
            }
            httpRequest = post;
        } else {
            httpRequest = new HttpGet(request.getUrl());
        }
        try {
            return execute(request, httpRequest);
        } catch (RemoteException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException("Cannot execute " + request, e);
        }
    }

    protected Object execute(Request request, HttpUriRequest httpReq)
            throws Exception {
        for (Map.Entry<String, String> entry : request.entrySet()) {
            httpReq.setHeader(entry.getKey(), entry.getValue());
        }
        HttpResponse resp = executeRequestWithTimeout(httpReq);
        HttpEntity entity = resp.getEntity();
        int status = resp.getStatusLine().getStatusCode();
        if (entity == null) {
            if (status < 400) {
                return null;
            }
            throw new RemoteException(status, "ServerError", "Server Error",
                    (Throwable) null);
        }
        Header ctypeHeader = entity.getContentType();
        if (ctypeHeader == null) { // handle broken responses with no ctype
            if (status != 200) {
                // this may happen when login failed
                throw new RemoteException(status, "ServerError",
                        "Server Error", (Throwable) null);
            }
            return null; // cannot handle responses with no ctype
        }
        String ctype = ctypeHeader.getValue();
        String disp = null;
        Header[] hdisp = resp.getHeaders("Content-Disposition");
        if (hdisp != null && hdisp.length > 0) {
            disp = hdisp[0].getValue();
        }
        return request.handleResult(status, ctype, disp, entity.getContent());
    }

    protected HttpResponse executeRequestWithTimeout(HttpUriRequest httpReq)
            throws Exception {

        // Set timeout for the socket, connection manager
        // and connection itself
        if (httpConnectionTimeout > 0) {
            HttpParams httpParams = http.getParams();
            httpParams.setIntParameter("http.socket.timeout",
                    httpConnectionTimeout);
            httpParams.setIntParameter("http.connection-manager.timeout",
                    httpConnectionTimeout);
            httpParams.setIntParameter("http.connection.timeout",
                    httpConnectionTimeout);
        }
        return http.execute(httpReq, ctx);
    }

}

@@ -21,17 +21,17 @@
 2006-201
-1
+4
  Nuxeo S
@@ -443,11 +443,20 @@
 ava.
+n
 io.
+charset.
 Unsu
@@ -458,32 +458,31 @@
 .Unsupported
-Encoding
+Charset
 Exception;%0Ai
@@ -546,16 +546,58 @@
 ipart;%0A%0A
+import org.apache.commons.codec.Charsets;%0A
 import o
@@ -976,16 +976,20 @@
 rotocol.
+Http
 ClientCo
@@ -1043,63 +1043,8 @@
 ty;%0A
-import org.apache.http.impl.client.AbstractHttpClient;%0A
 impo
@@ -1221,32 +1221,33 @@
 ol.HttpContext;%0A
+%0A
 import org.nuxeo
@@ -2756,16 +2756,20 @@
 tribute(
+Http
 ClientCo
@@ -3506,16 +3506,55 @@
 g(),
- %22UTF-8%22
+%0A                                Charsets.UTF_8
 );%0A 
@@ -3596,16 +3596,15 @@
 rted
-Encoding
+Charset
 Exce

Upgrade Apache HTTP components to 4.3.3