summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPContext.java
blob: 7132f8ead6e31720fa054dc000ae537b31d9bacf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package com.mapbox.mapboxsdk.http;

import android.text.TextUtils;
import android.util.Log;

import com.mapbox.mapboxsdk.constants.MapboxConstants;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.UnknownHostException;

import javax.net.ssl.SSLException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

class HTTPContext {

    private static final int CONNECTION_ERROR = 0;
    private static final int TEMPORARY_ERROR = 1;
    private static final int PERMANENT_ERROR = 2;
    private static final int CANCELED_ERROR = 3;

    private static HTTPContext mInstance = null;

    private OkHttpClient mClient;

    private HTTPContext() {
        super();
        mClient = new OkHttpClient();
        //mClient.interceptors().add(new LoggingInterceptor());
    }

    public static HTTPContext getInstance() {
        if (mInstance == null) {
            mInstance = new HTTPContext();
        }

        return mInstance;
    }

    public HTTPRequest createRequest(long nativePtr, String resourceUrl, String userAgent, String etag, String modified) {
        return new HTTPRequest(nativePtr, resourceUrl, userAgent, etag, modified);
    }

    public class HTTPRequest implements Callback {
        private final String LOG_TAG = HTTPRequest.class.getName();

        private long mNativePtr = 0;

        private Call mCall;
        private Request mRequest;

        private native void nativeOnFailure(long nativePtr, int type, String message);
        private native void nativeOnResponse(long nativePtr, int code, String message, String etag, String modified, String cacheControl, String expires, byte[] body);

        private HTTPRequest(long nativePtr, String resourceUrl, String userAgent, String etag, String modified) {
            mNativePtr = nativePtr;
            Request.Builder builder = new Request.Builder().url(resourceUrl).tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE)).addHeader("User-Agent", userAgent);
            if (etag.length() > 0) {
                builder = builder.addHeader("If-None-Match", etag);
            } else if (modified.length() > 0) {
                builder = builder.addHeader("If-Modified-Since", modified);
            }
            mRequest = builder.build();
        }

        public void start() {
            mCall = HTTPContext.getInstance().mClient.newCall(mRequest);
            mCall.enqueue(this);
        }

        public void cancel() {
            mCall.cancel();
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if (response.isSuccessful()) {
                Log.v(LOG_TAG, String.format("[HTTP] Request was successful (code = %d).", response.code()));
            } else {
                // We don't want to call this unsuccessful because a 304 isn't really an error
                String message = !TextUtils.isEmpty(response.message()) ? response.message() : "No additional information";
                Log.d(LOG_TAG, String.format(
                        "[HTTP] Request with response code = %d: %s",
                        response.code(), message));
            }

            byte[] body;
            try {
                body = response.body().bytes();
            } catch (IOException e) {
                onFailure(null, e);
                //throw e;
                return;
            } finally {
                response.body().close();
            }

            nativeOnResponse(mNativePtr, response.code(), response.message(), response.header("ETag"), response.header("Last-Modified"), response.header("Cache-Control"), response.header("Expires"), body);
        }

        @Override
        public void onFailure(Call call, IOException e) {
            Log.w(LOG_TAG, String.format("[HTTP] Request could not be executed: %s", e.getMessage()));

            int type = PERMANENT_ERROR;
            if ((e instanceof UnknownHostException) || (e instanceof SocketException) || (e instanceof ProtocolException) || (e instanceof SSLException)) {
                type = CONNECTION_ERROR;
            } else if ((e instanceof InterruptedIOException)) {
                type = TEMPORARY_ERROR;
            } else if (mCall.isCanceled()) {
                type = CANCELED_ERROR;
            }

            String errorMessage = e.getMessage() != null ? e.getMessage() : "Error processing the request";
            nativeOnFailure(mNativePtr, type, errorMessage);
        }

    }

    /*
     * Application interceptor that logs the outgoing request and the incoming response.
     * Based on https://github.com/square/okhttp/wiki/Interceptors
     */

    class LoggingInterceptor implements Interceptor {

        private final static String LOG_TAG = "LoggingInterceptor";

        @Override public Response intercept(Interceptor.Chain chain) throws IOException {
            Request request = chain.request();

            long t1 = System.nanoTime();
            Log.i(LOG_TAG, String.format("Sending request %s on %s%n%s",
                    request.url(), chain.connection(), request.headers()));

            Response response = chain.proceed(request);

            long t2 = System.nanoTime();
            Log.i(LOG_TAG, String.format("Received response for %s in %.1fms%n%s",
                    response.request().url(), (t2 - t1) / 1e6d, response.headers()));

            return response;
        }
    }
}