OkHttp
High-performance HTTP client for Java/Kotlin by Square, the Android development company. Built-in HTTP/2 support, connection pooling, GZIP compression, response caching, and automatic recovery from network failures. Optimized for Android and JVM platforms.
Library
OkHttp
Overview
OkHttp is developed as "a high-performance HTTP client for Android and Java" - an open-source library created by Square. It has established itself as the de facto industry standard for HTTP communication in Android applications, supporting both synchronous and asynchronous APIs. With built-in HTTP/2 support, automatic connection pooling, transparent GZIP compression, and response caching, it enables efficient network communication. Used as the underlying technology for major libraries like Retrofit and Picasso, it has become a core component of the Android ecosystem.
Details
OkHttp 2025 edition continues to evolve as the standard HTTP client for Android development, optimized for the latest HTTP specifications and Android platform. Supporting HTTP/1.1 and HTTP/2 completely, along with SPDY support, WebSocket functionality, and a customizable Interceptor system, it supports enterprise-level mobile application development. Through efficient connection management via ConnectionPool, automatic retry functionality, and detailed logging capabilities, it achieves both stability and performance. Integration with the Square ecosystem also enhances development efficiency in Android app network layers.
Key Features
- Android Optimization: Design and optimization specifically tailored for the Android platform
- Complete HTTP/2 Support: Multiplexing and efficient connection utilization
- Connection Pooling: Automatic connection reuse and performance improvement
- Interceptor System: Flexible customization of request and response processing
- Transparent Caching: Automatic response caching and offline support
- WebSocket Support: Built-in real-time communication functionality
Pros and Cons
Pros
- De facto standard in Android development with extensive track record and reliability
- High-speed communication and battery consumption optimization through HTTP/2 support
- Robust network processing through connection pooling and automatic retry
- Flexible customization through the Interceptor system
- Excellent integration with Square ecosystem (Retrofit, Moshi, etc.)
- Efficient debugging through detailed logging functionality
Cons
- Android/Java platform exclusive with no cross-platform support
- High learning cost and overhead for simple HTTP requests
- Increased APK size making applications larger
- Complex initial setup with many configuration options
- Additional considerations needed for integration with Kotlin coroutines
- Cannot be used in web environments (JavaScript)
Reference Pages
Code Examples
Installation and Basic Setup
// build.gradle (Module: app)
dependencies {
// Latest version of OkHttp
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
// Version with logging functionality (recommended for debugging)
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
// WebSocket functionality (if needed)
implementation 'com.squareup.okhttp3:okhttp-ws:4.12.0'
}
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Basic Requests (GET/POST/PUT/DELETE)
import okhttp3.*;
import java.io.IOException;
public class OkHttpExample {
private final OkHttpClient client = new OkHttpClient();
// Basic GET request (synchronous)
public void basicGetRequest() throws IOException {
Request request = new Request.Builder()
.url("https://api.example.com/users")
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
System.out.println("Response: " + responseBody);
// Get header information
System.out.println("Content-Type: " + response.header("Content-Type"));
System.out.println("Status Code: " + response.code());
} else {
System.out.println("Request failed: " + response.code());
}
}
}
// Asynchronous GET request
public void asyncGetRequest() {
Request request = new Request.Builder()
.url("https://api.example.com/users")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("Request failed: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String responseBody = response.body().string();
System.out.println("Async response: " + responseBody);
} else {
System.out.println("Async request failed: " + response.code());
}
response.close();
}
});
}
// POST request with JSON
public void postJsonRequest() throws IOException {
String json = "{\"name\": \"John Doe\", \"email\": \"[email protected]\"}";
RequestBody body = RequestBody.create(json, MediaType.parse("application/json"));
Request request = new Request.Builder()
.url("https://api.example.com/users")
.post(body)
.addHeader("Authorization", "Bearer your-token")
.addHeader("Content-Type", "application/json")
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
System.out.println("Created user: " + responseBody);
} else {
System.out.println("POST failed: " + response.code());
}
}
}
// PUT request (update)
public void putRequest() throws IOException {
String json = "{\"name\": \"Jane Doe\", \"email\": \"[email protected]\"}";
RequestBody body = RequestBody.create(json, MediaType.parse("application/json"));
Request request = new Request.Builder()
.url("https://api.example.com/users/123")
.put(body)
.addHeader("Authorization", "Bearer your-token")
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
System.out.println("User updated successfully");
}
}
}
// DELETE request
public void deleteRequest() throws IOException {
Request request = new Request.Builder()
.url("https://api.example.com/users/123")
.delete()
.addHeader("Authorization", "Bearer your-token")
.build();
try (Response response = client.newCall(request).execute()) {
if (response.code() == 204) {
System.out.println("User deleted successfully");
}
}
}
// Form data submission
public void submitFormData() throws IOException {
RequestBody formBody = new FormBody.Builder()
.add("username", "testuser")
.add("password", "secret123")
.add("remember", "true")
.build();
Request request = new Request.Builder()
.url("https://api.example.com/login")
.post(formBody)
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
System.out.println("Login response: " + responseBody);
}
}
}
}
Advanced Configuration and Customization (Headers, Authentication, Timeout, etc.)
import okhttp3.*;
import okhttp3.logging.HttpLoggingInterceptor;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class AdvancedOkHttpExample {
// Custom OkHttpClient configuration
public OkHttpClient createCustomClient() {
// Logging interceptor setup
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS) // Connection timeout
.readTimeout(60, TimeUnit.SECONDS) // Read timeout
.writeTimeout(60, TimeUnit.SECONDS) // Write timeout
.callTimeout(120, TimeUnit.SECONDS) // Overall call timeout
.retryOnConnectionFailure(true) // Enable automatic retry
.followRedirects(true) // Follow redirects
.followSslRedirects(true) // Follow SSL redirects
.addInterceptor(loggingInterceptor) // Add logging
.addInterceptor(new AuthInterceptor()) // Custom authentication
.connectionPool(new ConnectionPool(5, 10, TimeUnit.MINUTES)) // Connection pool
.build();
}
// Custom authentication interceptor
public static class AuthInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
// Add authentication header to all requests
Request authenticatedRequest = originalRequest.newBuilder()
.addHeader("Authorization", "Bearer " + getAuthToken())
.addHeader("User-Agent", "MyApp/1.0 (OkHttp)")
.addHeader("Accept", "application/json")
.build();
return chain.proceed(authenticatedRequest);
}
private String getAuthToken() {
// Get token from secure storage (SharedPreferences, Keystore, etc.)
return "your-jwt-token";
}
}
// Custom header configuration
public void requestWithCustomHeaders() throws IOException {
OkHttpClient client = createCustomClient();
Request request = new Request.Builder()
.url("https://api.example.com/protected")
.addHeader("X-API-Version", "v2")
.addHeader("X-Client-ID", "mobile-app")
.addHeader("Accept-Language", "en-US,ja-JP")
.addHeader("Cache-Control", "no-cache")
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
System.out.println("Protected resource: " + response.body().string());
}
}
}
// Cookie handling
public void handleCookies() throws IOException {
CookieJar cookieJar = new JavaNetCookieJar(java.net.CookieManager.getDefault());
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.build();
// First request (establishes cookies)
Request loginRequest = new Request.Builder()
.url("https://api.example.com/login")
.post(RequestBody.create("{\"username\":\"user\",\"password\":\"pass\"}",
MediaType.parse("application/json")))
.build();
try (Response loginResponse = client.newCall(loginRequest).execute()) {
if (loginResponse.isSuccessful()) {
System.out.println("Login successful");
// Subsequent request (automatically includes cookies)
Request protectedRequest = new Request.Builder()
.url("https://api.example.com/profile")
.build();
try (Response profileResponse = client.newCall(protectedRequest).execute()) {
System.out.println("Profile: " + profileResponse.body().string());
}
}
}
}
// HTTP/2 configuration
public void http2Example() throws IOException {
OkHttpClient client = new OkHttpClient.Builder()
.protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
.build();
Request request = new Request.Builder()
.url("https://api.example.com/http2-endpoint")
.build();
try (Response response = client.newCall(request).execute()) {
System.out.println("Protocol: " + response.protocol());
System.out.println("Response: " + response.body().string());
}
}
// Proxy configuration
public void proxyExample() throws IOException {
Proxy proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress("proxy.example.com", 8080));
OkHttpClient client = new OkHttpClient.Builder()
.proxy(proxy)
.proxyAuthenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("proxy-user", "proxy-pass");
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
}
})
.build();
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
try (Response response = client.newCall(request).execute()) {
System.out.println("Via proxy: " + response.body().string());
}
}
}
Error Handling and Retry Functionality
import okhttp3.*;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
public class ErrorHandlingExample {
private final OkHttpClient client;
public ErrorHandlingExample() {
this.client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.addInterceptor(new RetryInterceptor(3)) // Custom retry interceptor
.build();
}
// Comprehensive error handling
public String safeRequest(String url) {
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
handleHttpError(response);
return null;
}
return response.body().string();
} catch (SocketTimeoutException e) {
System.err.println("Request timeout: " + e.getMessage());
System.err.println("Please check your network connection or increase timeout");
} catch (UnknownHostException e) {
System.err.println("Host not found: " + e.getMessage());
System.err.println("Please check the URL or your internet connection");
} catch (IOException e) {
System.err.println("Network error: " + e.getMessage());
System.err.println("Please try again later");
}
return null;
}
private void handleHttpError(Response response) throws IOException {
int statusCode = response.code();
String errorBody = response.body() != null ? response.body().string() : "No error details";
switch (statusCode) {
case 400:
System.err.println("Bad Request (400): Invalid request parameters");
System.err.println("Error details: " + errorBody);
break;
case 401:
System.err.println("Unauthorized (401): Authentication required");
// Trigger token refresh or re-login
refreshAuthToken();
break;
case 403:
System.err.println("Forbidden (403): Access denied");
System.err.println("Check your permissions");
break;
case 404:
System.err.println("Not Found (404): Resource not found");
break;
case 429:
String retryAfter = response.header("Retry-After");
System.err.println("Rate Limited (429): Too many requests");
if (retryAfter != null) {
System.err.println("Retry after: " + retryAfter + " seconds");
}
break;
case 500:
System.err.println("Internal Server Error (500): Server problem");
break;
case 502:
System.err.println("Bad Gateway (502): Server temporarily unavailable");
break;
case 503:
System.err.println("Service Unavailable (503): Server overloaded");
break;
default:
System.err.println("HTTP Error " + statusCode + ": " + response.message());
System.err.println("Error details: " + errorBody);
}
}
// Custom retry interceptor
public static class RetryInterceptor implements Interceptor {
private final int maxRetries;
public RetryInterceptor(int maxRetries) {
this.maxRetries = maxRetries;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = null;
IOException exception = null;
for (int attempt = 0; attempt <= maxRetries; attempt++) {
try {
response = chain.proceed(request);
// Retry on specific status codes
if (response.isSuccessful() || !shouldRetry(response.code())) {
return response;
}
response.close();
if (attempt < maxRetries) {
long delay = calculateDelay(attempt);
System.out.println("Retrying request in " + delay + "ms (attempt " + (attempt + 1) + ")");
Thread.sleep(delay);
}
} catch (IOException e) {
exception = e;
if (attempt < maxRetries) {
long delay = calculateDelay(attempt);
System.out.println("Network error, retrying in " + delay + "ms: " + e.getMessage());
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted during retry delay", ie);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted during retry", e);
}
}
if (response != null) {
return response;
} else {
throw new IOException("Request failed after " + maxRetries + " retries", exception);
}
}
private boolean shouldRetry(int statusCode) {
return statusCode == 408 || // Request Timeout
statusCode == 429 || // Too Many Requests
statusCode == 500 || // Internal Server Error
statusCode == 502 || // Bad Gateway
statusCode == 503 || // Service Unavailable
statusCode == 504; // Gateway Timeout
}
private long calculateDelay(int attempt) {
// Exponential backoff: 1s, 2s, 4s, 8s...
return Math.min(1000L * (1L << attempt), 10000L);
}
}
// Asynchronous error handling
public void asyncRequestWithErrorHandling(String url) {
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
if (call.isCanceled()) {
System.out.println("Request was cancelled");
} else if (e instanceof SocketTimeoutException) {
System.err.println("Request timeout: " + e.getMessage());
} else if (e instanceof UnknownHostException) {
System.err.println("Network unavailable: " + e.getMessage());
} else {
System.err.println("Network error: " + e.getMessage());
}
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {
if (response.isSuccessful()) {
String responseBody = response.body().string();
System.out.println("Success: " + responseBody);
} else {
handleHttpError(response);
}
} finally {
response.close();
}
}
});
}
private void refreshAuthToken() {
// Implement token refresh logic
System.out.println("Refreshing authentication token...");
}
// Circuit breaker pattern implementation
public static class CircuitBreaker {
private int failureCount = 0;
private long lastFailureTime = 0;
private final int failureThreshold;
private final long timeout;
public CircuitBreaker(int failureThreshold, long timeoutMillis) {
this.failureThreshold = failureThreshold;
this.timeout = timeoutMillis;
}
public boolean allowRequest() {
if (failureCount < failureThreshold) {
return true;
}
return System.currentTimeMillis() - lastFailureTime >= timeout;
}
public void recordSuccess() {
this.failureCount = 0;
}
public void recordFailure() {
this.failureCount++;
this.lastFailureTime = System.currentTimeMillis();
}
}
}
Concurrent Processing and Asynchronous Requests
import okhttp3.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class ConcurrentRequestsExample {
private final OkHttpClient client;
private final ExecutorService executor;
public ConcurrentRequestsExample() {
this.client = new OkHttpClient.Builder()
.connectionPool(new ConnectionPool(10, 10, TimeUnit.MINUTES))
.dispatcher(new Dispatcher(Executors.newFixedThreadPool(10)))
.build();
this.executor = Executors.newFixedThreadPool(20);
}
// Parallel request execution
public List<String> fetchMultipleUrls(List<String> urls) throws InterruptedException {
List<Future<String>> futures = new ArrayList<>();
List<String> results = new ArrayList<>();
// Submit all requests
for (String url : urls) {
Future<String> future = executor.submit(() -> {
try {
Request request = new Request.Builder().url(url).build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
return response.body().string();
} else {
return "Error: " + response.code();
}
}
} catch (IOException e) {
return "Exception: " + e.getMessage();
}
});
futures.add(future);
}
// Collect results
for (Future<String> future : futures) {
try {
String result = future.get(30, TimeUnit.SECONDS);
results.add(result);
} catch (ExecutionException | TimeoutException e) {
results.add("Failed: " + e.getMessage());
}
}
return results;
}
// Asynchronous parallel requests with callbacks
public void fetchMultipleAsync(List<String> urls, ResponseCallback callback) {
CountDownLatch latch = new CountDownLatch(urls.size());
List<String> results = Collections.synchronizedList(new ArrayList<>());
for (String url : urls) {
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
results.add("Failed: " + e.getMessage());
latch.countDown();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {
if (response.isSuccessful()) {
results.add(response.body().string());
} else {
results.add("Error: " + response.code());
}
} finally {
response.close();
latch.countDown();
}
}
});
}
// Wait for all requests to complete in background thread
executor.submit(() -> {
try {
latch.await(60, TimeUnit.SECONDS);
callback.onComplete(results);
} catch (InterruptedException e) {
callback.onError(e);
}
});
}
// Pagination with concurrent processing
public List<String> fetchAllPages(String baseUrl, int maxPages) throws InterruptedException {
List<Future<String>> futures = new ArrayList<>();
for (int page = 1; page <= maxPages; page++) {
final int currentPage = page;
Future<String> future = executor.submit(() -> {
try {
String url = baseUrl + "?page=" + currentPage + "&limit=20";
Request request = new Request.Builder().url(url).build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
System.out.println("Page " + currentPage + " completed");
return responseBody;
} else {
return null;
}
}
} catch (IOException e) {
System.err.println("Page " + currentPage + " failed: " + e.getMessage());
return null;
}
});
futures.add(future);
}
List<String> allData = new ArrayList<>();
for (Future<String> future : futures) {
try {
String pageData = future.get(30, TimeUnit.SECONDS);
if (pageData != null) {
allData.add(pageData);
}
} catch (ExecutionException | TimeoutException e) {
System.err.println("Page fetch failed: " + e.getMessage());
}
}
return allData;
}
// Rate limiting with semaphore
public void fetchWithRateLimit(List<String> urls, int maxConcurrent) {
Semaphore semaphore = new Semaphore(maxConcurrent);
CountDownLatch latch = new CountDownLatch(urls.size());
for (String url : urls) {
executor.submit(() -> {
try {
semaphore.acquire(); // Wait for permit
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.err.println("Request failed: " + e.getMessage());
semaphore.release();
latch.countDown();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try {
if (response.isSuccessful()) {
String body = response.body().string();
System.out.println("Response received: " + body.length() + " chars");
}
} finally {
response.close();
semaphore.release();
latch.countDown();
}
}
});
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
latch.countDown();
}
});
}
try {
latch.await(120, TimeUnit.SECONDS);
System.out.println("All requests completed");
} catch (InterruptedException e) {
System.err.println("Interrupted while waiting for completion");
}
}
// Streaming download with progress
public void downloadLargeFile(String url, String filename) throws IOException {
Request request = new Request.Builder().url(url).build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("Download failed: " + response.code());
}
long contentLength = response.body().contentLength();
System.out.println("File size: " + contentLength + " bytes");
try (InputStream inputStream = response.body().byteStream();
FileOutputStream outputStream = new FileOutputStream(filename)) {
byte[] buffer = new byte[8192];
long downloaded = 0;
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
downloaded += bytesRead;
if (contentLength > 0) {
int progress = (int) ((downloaded * 100) / contentLength);
System.out.print("\rDownload progress: " + progress + "%");
}
}
System.out.println("\nDownload completed: " + filename);
}
}
}
public interface ResponseCallback {
void onComplete(List<String> results);
void onError(Exception error);
}
public void shutdown() {
executor.shutdown();
client.dispatcher().executorService().shutdown();
client.connectionPool().evictAll();
}
}
Framework Integration and Practical Examples
// Android integration with Retrofit
public interface ApiService {
@GET("users/{id}")
Call<User> getUser(@Path("id") int userId);
@POST("users")
Call<User> createUser(@Body CreateUserRequest request);
}
public class AndroidHttpExample {
private final ApiService apiService;
private final OkHttpClient okHttpClient;
public AndroidHttpExample() {
// Custom OkHttpClient for Retrofit
this.okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new AuthInterceptor())
.addInterceptor(new LoggingInterceptor())
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/v1/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
this.apiService = retrofit.create(ApiService.class);
}
// Android-specific authentication interceptor
public class AuthInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
// Get token from Android SharedPreferences
SharedPreferences prefs = context.getSharedPreferences("auth", Context.MODE_PRIVATE);
String token = prefs.getString("access_token", null);
if (token != null) {
Request authenticatedRequest = originalRequest.newBuilder()
.addHeader("Authorization", "Bearer " + token)
.build();
return chain.proceed(authenticatedRequest);
}
return chain.proceed(originalRequest);
}
}
// File upload with progress (Android)
public void uploadFileWithProgress(File file, ProgressCallback callback) {
RequestBody fileBody = RequestBody.create(file, MediaType.parse("image/*"));
// Progress tracking request body
ProgressRequestBody progressRequestBody = new ProgressRequestBody(fileBody, callback);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), progressRequestBody);
Request request = new Request.Builder()
.url("https://api.example.com/upload")
.post(new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addPart(filePart)
.addFormDataPart("description", "Uploaded from Android")
.build())
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
callback.onError(e);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
callback.onSuccess(response.body().string());
} else {
callback.onError(new IOException("Upload failed: " + response.code()));
}
response.close();
}
});
}
// Progress tracking RequestBody
public static class ProgressRequestBody extends RequestBody {
private final RequestBody delegate;
private final ProgressCallback callback;
public ProgressRequestBody(RequestBody delegate, ProgressCallback callback) {
this.delegate = delegate;
this.callback = callback;
}
@Override
public MediaType contentType() {
return delegate.contentType();
}
@Override
public long contentLength() throws IOException {
return delegate.contentLength();
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
CountingSink countingSink = new CountingSink(sink);
BufferedSink bufferedSink = Okio.buffer(countingSink);
delegate.writeTo(bufferedSink);
bufferedSink.flush();
}
private class CountingSink extends ForwardingSink {
private long bytesWritten = 0;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
bytesWritten += byteCount;
if (callback != null) {
callback.onProgress(bytesWritten, contentLength());
}
}
}
}
public interface ProgressCallback {
void onProgress(long bytesWritten, long contentLength);
void onSuccess(String response);
void onError(Exception error);
}
// WebSocket implementation
public void establishWebSocketConnection() {
Request request = new Request.Builder()
.url("wss://api.example.com/websocket")
.build();
WebSocketListener listener = new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
System.out.println("WebSocket connected");
webSocket.send("Hello, Server!");
}
@Override
public void onMessage(WebSocket webSocket, String text) {
System.out.println("Received: " + text);
// Handle incoming message
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
System.err.println("WebSocket error: " + t.getMessage());
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(1000, null);
System.out.println("WebSocket closing: " + reason);
}
};
WebSocket webSocket = okHttpClient.newWebSocket(request, listener);
}
// Certificate pinning for enhanced security
public OkHttpClient createSecureClient() {
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("api.example.com", "sha256/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=")
.build();
return new OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
}
}