org.quantumbadger.redreader.http.okhttp.OKHTTPBackend.java Source code

Java tutorial

Introduction

Here is the source code for org.quantumbadger.redreader.http.okhttp.OKHTTPBackend.java

Source

/*******************************************************************************
 * This file is part of RedReader.
 *
 * RedReader is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedReader is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedReader.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

package org.quantumbadger.redreader.http.okhttp;

import android.content.Context;
import com.squareup.okhttp.CacheControl;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
import org.quantumbadger.redreader.cache.CacheRequest;
import org.quantumbadger.redreader.common.Constants;
import org.quantumbadger.redreader.common.TorCommon;
import org.quantumbadger.redreader.http.HTTPBackend;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

public class OKHTTPBackend implements HTTPBackend {

    private final OkHttpClient mClient;
    private static HTTPBackend httpBackend;

    private OKHTTPBackend() {

        mClient = new OkHttpClient();

        if (TorCommon.isTorEnabled()) {
            Proxy tor = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8118));
            //SOCKS appears to be broken for now, Relevant: https://github.com/square/okhttp/issues/2315
            mClient.setProxy(tor);
        }

        mClient.setFollowRedirects(true);
        mClient.setFollowSslRedirects(true);

        mClient.setConnectTimeout(15000, TimeUnit.SECONDS);
        mClient.setReadTimeout(10000, TimeUnit.SECONDS);

        mClient.setRetryOnConnectionFailure(true);
    }

    public static synchronized HTTPBackend getHttpBackend() {
        if (httpBackend == null) {
            httpBackend = new OKHTTPBackend();
        }
        return httpBackend;
    }

    public static synchronized void recreateHttpBackend() {
        httpBackend = new OKHTTPBackend();
    }

    @Override
    public Request prepareRequest(final Context context, final RequestDetails details) {

        final com.squareup.okhttp.Request.Builder builder = new com.squareup.okhttp.Request.Builder();

        builder.header("User-Agent", Constants.ua(context));

        final List<PostField> postFields = details.getPostFields();

        if (postFields != null) {
            builder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"),
                    PostField.encodeList(postFields)));

        } else {
            builder.get();
        }

        builder.url(details.getUrl().toString());
        builder.cacheControl(CacheControl.FORCE_NETWORK);

        final AtomicReference<Call> callRef = new AtomicReference<>();

        return new Request() {

            public void executeInThisThread(final Listener listener) {

                final Call call = mClient.newCall(builder.build());
                callRef.set(call);

                try {

                    final Response response;

                    try {
                        response = call.execute();
                    } catch (IOException e) {
                        listener.onError(CacheRequest.REQUEST_FAILURE_CONNECTION, e, null);
                        return;
                    }

                    final int status = response.code();

                    if (status == 200 || status == 202) {

                        final ResponseBody body = response.body();
                        final InputStream bodyStream;
                        final Long bodyBytes;

                        if (body != null) {
                            bodyStream = body.byteStream();
                            bodyBytes = body.contentLength();

                        } else {
                            // TODO error
                            bodyStream = null;
                            bodyBytes = null;
                        }

                        final String contentType = response.header("Content-Type");

                        listener.onSuccess(contentType, bodyBytes, bodyStream);

                    } else {
                        listener.onError(CacheRequest.REQUEST_FAILURE_REQUEST, null, status);
                    }

                } catch (Throwable t) {
                    listener.onError(CacheRequest.REQUEST_FAILURE_CONNECTION, t, null);
                }
            }

            @Override
            public void cancel() {
                final Call call = callRef.getAndSet(null);
                if (call != null) {
                    call.cancel();
                }
            }

            @Override
            public void addHeader(final String name, final String value) {
                builder.addHeader(name, value);
            }
        };
    }
}