public static Gson gson() {
    return builder.create();
} public static final String CONTENT_LENGTH_HEADER = "Content-Length"; public static final String CONTENT_TYPE_HEADER = "Content-Type"; public static final String DELETE_METHOD = "DELETE"; public static final String GET_METHOD = "GET"; public static final Charset OIO_CHARSET = Charset.forName("UTF-8"); public static final String OIO_REQUEST_ID_HEADER = "X-oio-req-id"; public static final String OIO_TIMEOUT_HEADER = "X-oio-timeout"; public static final String POST_METHOD = "POST"; public static final String PUT_METHOD = "PUT"; public static boolean nullOrEmpty(String string) {
    return null == string || 0 == string.length();
} public class RequestContext {

    private DeadlineManager dm;

    private String reqId = null;
    private int reqStart = -1;
    private int rawTimeout = -1;
    private int deadline = -1;

    /**
     * Build a new {@link RequestContext} with a default 30s timeout.
     */
    public RequestContext() {
        this.dm = DeadlineManager.instance();
    }

    /**
     * Copy constructor. Build a new {@link RequestContext} from another one.
     * This will keep the request ID, the timeout and the deadline (if there is one).
     *
     * @param src The {@link RequestContext} to copy.
     */
    public RequestContext(RequestContext src) {
        this.withRequestId(src.requestId());
        this.deadline = src.deadline;
        this.rawTimeout = src.rawTimeout;
    }

    /* -- Request IDs ----------------------------------------------------- */

    /**
     * Ensure this request has an ID and it is at least 8 characters.
     *
     * @return this
     */
    public RequestContext ensureRequestId() {
        if (this.reqId == null)
            this.reqId = IdGen.requestId();
        else if (this.reqId.length() < 8)
            this.reqId += IdGen.requestId().substring(8 - this.reqId.length());
        return this;
    }

    /**
     * Get the request ID.
     *
     * @return the request ID (auto-generated if not set)
     */
    public String requestId() {
        return this.ensureRequestId().reqId;
    }

    /**
     * Set a request ID.
     *
     * @param requestId
     *            a request ID string. If is null, it will be auto-generated. If
     *            it is less than 8 characters, it will be suffixed.
     * @return this
     */
    public RequestContext withRequestId(String requestId) {
        this.reqId = requestId;
        return this;
    }

    /* -- Deadlines and timeouts ------------------------------------------ */

    /**
     * Compute a deadline from the {@link #timeout()}. This also means that the
     * timeout will be recomputed for each unique sub-request resulting from an
     * API call. If this request has started, compute the timeout from the start,
     * otherwise compute it from now.
     *
     * @return {@code this}
     */
    public RequestContext computeDeadline() {
        if (!this.hasTimeout())
            throw new IllegalStateException("No timeout has been set, cannot compute deadline");
        if (this.hasStarted())
            this.deadline = dm.timeoutToDeadline(this.rawTimeout, this.reqStart);
        else
            this.deadline = dm.timeoutToDeadline(this.rawTimeout);
        return this;
    }

    /**
     * Get the deadline for this request.
     *
     * If a timeout has been set ({@link #withTimeout(int)}) but no
     * deadline, {@link #computeDeadline()} will be called.
     *
     * @return the overall deadline for this request, in milliseconds
     */
    public int deadline() {
        if (!hasDeadline()) {
            startTiming();
            computeDeadline();
        }
        return this.deadline;
    }

    /**
     * Tell the time elapsed since this request has started.
     *
     * @return the duration since this request has started, in milliseconds
     */
    public int elapsed() {
        if (!this.hasStarted())
            return 0;
        return this.dm.now() - this.reqStart;
    }

    /**
     * Tell whether this request has a deadline or not. This will always return
     * {@code true} after {@link #computeDeadline()} or {@link #deadline()} has been
     * called.
     *
     * @return {@code true} if this request has a deadline.
     */
    public boolean hasDeadline() {
        return this.deadline >= 0;
    }

    /**
     * Tell if this request has started.
     *
     * @return {@code true} if this request has started.
     */
    public boolean hasStarted() {
        return this.reqStart >= 0;
    }

    /**
     * Tell whether this request has a timeout or not.
     *
     * @return {@code true} if this request has timeout.
     */
    public boolean hasTimeout() {
        return this.rawTimeout >= 0;
    }

    /**
     * Reset the deadline set on this request. This must be called when reusing
     * a context only for its timeout and request ID.
     *
     * @return {@code this}
     */
    public RequestContext resetDeadline() {
        this.deadline = -1;
        return this;
    }

    /**
     * Start timing this request.
     *
     * @return this
     */
    public RequestContext startTiming() {
        this.reqStart = dm.now();
        return this;
    }

    /**
     * Get the timeout for the request.
     *
     * If {@link #hasDeadline()} returns {@code true}, successive calls to this
     * method will return decreasing values, and negative values when the
     * deadline has been exceeded.
     *
     * @return the timeout for this request, in milliseconds
     */
    public int timeout() {
        if (this.hasDeadline())
            return this.dm.deadlineToTimeout(this.deadline);
        return this.rawTimeout;
    }

    /**
     * Set a deadline on the whole request.
     *
     * This will reset any previous timeout set with {@link #withTimeout(int)} to the duration
     * from now to the deadline.
     *
     * @param deadline the deadline in milliseconds
     * @return this
     */
    public RequestContext withDeadline(int deadline) {
        checkArgument(deadline >= 0, "deadline cannot be negative");
        this.deadline = deadline;
        this.rawTimeout = this.dm.deadlineToTimeout(deadline);
        return this;
    }

    /**
     * Set a timeout for each unique sub-request resulting from an API call.
     *
     * This will reset any previous deadline set with {@link #withDeadline(int)}.
     *
     * The timeout will be used to compute the deadline when
     * {@link #startTiming()} or {@link #deadline()} is called.
     *
     * @param timeout
     *            a timeout in milliseconds
     * @return this
     */
    public RequestContext withTimeout(int timeout) {
        checkArgument(timeout > 0, "timeout cannot be negative");
        this.rawTimeout = timeout;
        this.resetDeadline();
        return this;
    }
} public class Check {

	/**
	 * Checks the specified condition and throw an {@code IllegalArgumentException} if {@code false}
	 * @param condition the condition to check
	 * @param msg the message to set in the exception
	 * @throws IllegalArgumentException if the specified condition is {@code false}
	 */
    public static void checkArgument(boolean condition, String msg) {
        if (!condition)
            throw new IllegalArgumentException(msg);
    }
    
    /**
	 * Checks the specified condition and throw an {@code IllegalArgumentException} if {@code false}
	 * @param condition the condition to check
	 * @throws IllegalArgumentException if the specified condition is {@code false}
	 */
    public static void checkArgument(boolean condition) {
        if (!condition)
            throw new IllegalArgumentException();
    }
} public interface SocketProvider {

    public Socket getSocket(String host, int port);
    public Socket getSocket(InetSocketAddress addr);

    public boolean reusableSocket();

} public class DeadlineManager {

    public interface ClockSource {
        /**
         *
         * @return the current time in milliseconds
         */
        int now();
    }

    private class SystemClockSource implements ClockSource {

        public SystemClockSource() {
        }

        @Override
        public int now() {
            return (int) (System.nanoTime() / 1000000);
        }
    }


    private static volatile DeadlineManager instance = null;

    private ClockSource clock;

    private DeadlineManager() {
        useSystemClockSource();
    }

    /**
     * Get the single instance of {@link DeadlineManager}.
     * @return the single instance of {@link DeadlineManager}
     */
    public static DeadlineManager instance() {
        if (instance == null) {
            synchronized (DeadlineManager.class) {
                if (instance == null) {
                    instance = new DeadlineManager();
                }
            }
        }
        return instance;
    }

    /**
     * Force the DeadlineManager to use a mocked {@link ClockSource}
     * @param clockSource The new clock source to use
     */
    public void useMockedClockSource(ClockSource clockSource) {
        this.clock = clockSource;
    }

    /**
     * Force the DeadlineManager to use the system monotonic clock source.
     */
    public void useSystemClockSource() {
        this.clock = this.new SystemClockSource();
    }

    /**
     * Raise an exception when a deadline has been reached.
     * 
     * @param deadline the deadline, in milliseconds
     * @throws DeadlineReachedException when the deadline has been reached
     */
    public void checkDeadline(int deadline) throws DeadlineReachedException {
        checkDeadline(deadline, now());
    }

    /**
     * Raise an exception when a deadline has been reached.
     * 
     * @param deadline the deadline, in milliseconds
     * @param refTime the reference time for the deadline, in milliseconds
     * @throws DeadlineReachedException when the deadline has been reached
     */
    public void checkDeadline(int deadline, int refTime) throws DeadlineReachedException {
        int diff = deadline - refTime;
        if (diff <= 0) {
            throw new DeadlineReachedException(-diff);
        }
    }

    /**
     * Convert a deadline to a timeout.
     *
     * @param deadline the deadline to convert, in milliseconds
     * @return a timeout in milliseconds
     */
    public int deadlineToTimeout(int deadline) {
        return deadline - now();
    }

    /**
     * Convert a deadline to a timeout.
     *
     * @param deadline the deadline to convert, in milliseconds
     * @param refTime the reference time for the deadline, in monotonic milliseconds
     * @return a timeout in milliseconds
     */
    public int deadlineToTimeout(int deadline, int refTime) {
        return deadline - refTime;
    }

    /**
     * Get the current monotonic time in milliseconds.
     *
     * @return The current monotonic time in milliseconds
     */
    public int now() {
        return clock.now();
    }

    /**
     * Convert a timeout to a deadline.
     *
     * @param timeout the timeout in milliseconds
     * @return a deadline in monotonic milliseconds
     */
    public int timeoutToDeadline(int timeout) {
        return timeoutToDeadline(timeout, now());
    }

    /**
     * Convert a timeout to a deadline.
     *
     * @param timeout the timeout in milliseconds
     * @param refTime the reference time for the deadline, in milliseconds
     * @return a deadline in monotonic milliseconds
     */
    public int timeoutToDeadline(int timeout, int refTime) {
        return refTime + timeout;
    }
} @SuppressWarnings("deprecation")
public class OioException extends SdsException {

    /**
     * 
     */
    private static final long serialVersionUID = 3270900242235005338L;

    public OioException(String message) {
        super(message);
    }

    public OioException(String message, Throwable t) {
        super(message, t);
    }
} public class OioSystemException extends OioException {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public OioSystemException(String message) {
        super(message);
    }

    public OioSystemException(String message, Throwable t) {
        super(message, t);
    }
} public interface SdsLogger {

    /**
     * Logs a message at {@link Level#FINEST}.
     *
     * @param message
     *            the message to log.
     */
    public void trace(String message);

    /**
     * Logs a throwable at {@link Level#FINEST}. The message of the Throwable
     * will be the message.
     *
     * @param thrown
     *            the Throwable to log.
     */
    public void trace(Throwable thrown);

    /**
     * Logs message with associated throwable information at
     * {@link Level#FINEST}.
     *
     * @param message
     *            the message to log
     * @param thrown
     *            the Throwable associated to the message.
     */
    public void trace(String message, Throwable thrown);

    /**
     * Checks if the {@link Level#FINEST} is enabled.
     *
     * @return true if enabled, false otherwise.
     */
    public boolean isTraceEnabled();

    /**
     * Logs a message at {@link Level#FINE}.
     *
     * @param message
     *            the message to log.
     */
    public void debug(String message);
    
    /**
     * Logs message with associated throwable information at
     * {@link Level#FINE}.
     *
     * @param message
     *            the message to log
     * @param thrown
     *            the Throwable associated to the message.
     */
    public void debug(String message, Throwable thrown);

    /**
     * Checks if the {@link Level#FINE} is enabled.
     *
     * @return true if enabled, false otherwise.
     */
    public boolean isDebugEnabled();

    /**
     * Logs a message at {@link Level#INFO}.
     *
     * @param message
     *            the message to log.
     */
    public void info(String message);

    /**
     * Logs a message at {@link Level#WARNING}.
     *
     * @param message
     *            the message to log.
     */
    public void warn(String message);

    /**
     * Logs a throwable at {@link Level#WARNING}. The message of the Throwable
     * will be the message.
     *
     * @param thrown
     *            the Throwable to log.
     */
    public void warn(Throwable thrown);

    /**
     * Logs message with associated throwable information at
     * {@link Level#WARNING}.
     *
     * @param message
     *            the message to log
     * @param thrown
     *            the Throwable associated to the message.
     */
    public void warn(String message, Throwable thrown);

    /**
     * Logs a message at {@link Level#SEVERE}.
     *
     * @param message
     *            the message to log.
     */
    public void error(String message);

    /**
     * Logs a throwable at {@link Level#SEVERE}. The message of the Throwable
     * will be the message.
     *
     * @param thrown
     *            the Throwable to log.
     */
    public void error(Throwable thrown);

    /**
     * Logs message with associated throwable information at
     * {@link Level#SEVERE}.
     *
     * @param message
     *            the message to log
     * @param thrown
     *            the Throwable associated to the message.
     */
    public void error(String message, Throwable thrown);
} public class SdsLoggerFactory {

    private static int loaded = -1;

    public static SdsLogger getLogger(Class<?> c) {
        ensureLoaded();
        switch (loaded) {
        case 1:
            return new Log4jLogger(c);
        case 0:
        default:
            return new BaseLogger(c);
        }
    }

    private static void ensureLoaded() {
        if (-1 == loaded) {
            try {
                Class.forName("org.apache.log4j.LogManager");
                loaded = 1;
            } catch (ClassNotFoundException e) {
                loaded = 0;
            }
        }
    }

}
import static io.openio.sds.common.JsonUtils.gson;
import static io.openio.sds.common.OioConstants.CONTENT_LENGTH_HEADER;
import static io.openio.sds.common.OioConstants.CONTENT_TYPE_HEADER;
import static io.openio.sds.common.OioConstants.DELETE_METHOD;
import static io.openio.sds.common.OioConstants.GET_METHOD;
import static io.openio.sds.common.OioConstants.OIO_CHARSET;
import static io.openio.sds.common.OioConstants.OIO_REQUEST_ID_HEADER;
import static io.openio.sds.common.OioConstants.OIO_TIMEOUT_HEADER;
import static io.openio.sds.common.OioConstants.POST_METHOD;
import static io.openio.sds.common.OioConstants.PUT_METHOD;
import static io.openio.sds.common.Strings.nullOrEmpty;
import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gson.stream.JsonReader;
import io.openio.sds.RequestContext;
import io.openio.sds.common.Check;
import io.openio.sds.common.SocketProvider;
import io.openio.sds.common.DeadlineManager;
import io.openio.sds.exceptions.OioException;
import io.openio.sds.exceptions.OioSystemException;
import io.openio.sds.logging.SdsLogger;
import io.openio.sds.logging.SdsLoggerFactory;
package io.openio.sds.http;





/**
 * Simple HTTP client
 * 
 * @author Christopher Dedeurwaerder
 * @author Florent Vennetier
 */
public class OioHttp {

    private static final SdsLogger logger = SdsLoggerFactory.getLogger(SdsLogger.class);

    private static final String CRLF = "\r\n";

    private static final byte[] CRLF_BYTES = { '\r', '\n' };

    private OioHttpSettings settings;

    private SocketProvider socketProvider;

    private OioHttp(OioHttpSettings settings, SocketProvider socketProvider) {
        this.settings = settings;
        this.socketProvider = socketProvider;
    }

    public static OioHttp http(OioHttpSettings settings, SocketProvider socketProvider) {
        Check.checkArgument(null != settings);
        Check.checkArgument(null != socketProvider);
        return new OioHttp(settings, socketProvider);
    }

    public RequestBuilder post(String uri) {
        Check.checkArgument(!nullOrEmpty(uri));
        return new RequestBuilder().req(POST_METHOD, uri);
    }

    public RequestBuilder put(String uri) {
        Check.checkArgument(!nullOrEmpty(uri));
        return new RequestBuilder().req(PUT_METHOD, uri);
    }

    public RequestBuilder get(String uri) {
        Check.checkArgument(!nullOrEmpty(uri));
        return new RequestBuilder().req(GET_METHOD, uri);
    }

    public RequestBuilder delete(String uri) {
        Check.checkArgument(!nullOrEmpty(uri));
        return new RequestBuilder().req(DELETE_METHOD, uri);
    }


    public static String timeoutMillisToStringMicros(int timeout) {
        // oio-proxy wants microseconds, and we remove 1% for the parsing overhead.
        return String.valueOf(timeout * 990);
    }

    public class RequestBuilder {

        private String method;
        private HashMap<String, String> headers = new HashMap<String, String>();
        private HashMap<String, String> query = new HashMap<String, String>();
        private String body;
        private InputStream data;
        private Long len;
        private URI uri;
        private OioHttpResponseVerifier verifier = null;
        private boolean chunked;
        private List<InetSocketAddress> hosts = null;
        private RequestContext reqCtx = null;