1 // Copyright 2022 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.net.apihelpers; 6 7 import androidx.annotation.Nullable; 8 9 import org.chromium.net.CallbackException; 10 import org.chromium.net.CronetException; 11 import org.chromium.net.UrlRequest; 12 import org.chromium.net.UrlResponseInfo; 13 14 import java.nio.ByteBuffer; 15 16 /** 17 * An implementation of {@link UrlRequest.Callback} that takes away the difficulty of managing the 18 * request lifecycle away, and automatically proceeds to read the response entirely. 19 */ 20 public abstract class ImplicitFlowControlCallback extends UrlRequest.Callback { 21 private static final int BYTE_BUFFER_CAPACITY = 32 * 1024; 22 23 /** 24 * Invoked whenever a redirect is encountered. This will only be invoked between the call to 25 * {@link UrlRequest#start} and {@link UrlRequest.Callback#onResponseStarted 26 * onResponseStarted()}. The body of the redirect response, if it has one, will be ignored. 27 * 28 * @param info Response information. 29 * @param newLocationUrl Location where request is redirected. 30 * @return true if the redirect should be followed, false if the request should be canceled. 31 * @throws Exception if an error occurs while processing a redirect. {@link #onFailed} will be 32 * called with the thrown exception set as the cause of the {@link CallbackException}. 33 */ shouldFollowRedirect(UrlResponseInfo info, String newLocationUrl)34 protected abstract boolean shouldFollowRedirect(UrlResponseInfo info, String newLocationUrl) 35 throws Exception; 36 37 /** 38 * Invoked when the final set of headers, after all redirects, is received. Will only be invoked 39 * once for each request. It's guaranteed that Cronet doesn't start reading the body until this 40 * method returns. 41 * 42 * @param info Response information. 43 * @throws Exception if an error occurs while processing response start. {@link #onFailed} will 44 * be 45 * called with the thrown exception set as the cause of the {@link CallbackException}. 46 */ onResponseStarted(UrlResponseInfo info)47 protected abstract void onResponseStarted(UrlResponseInfo info) throws Exception; 48 49 /** 50 * Invoked whenever part of the response body has been read. Only part of the buffer may be 51 * populated, even if the entire response body has not yet been consumed. The buffer is ready 52 * for reading. Buffers are reused internally so the implementing class shouldn't store the 53 * buffer or use it anywhere else than in the implementation of this method. 54 * 55 * @param info Response information. 56 * @param bodyChunk The buffer that contains the received data, flipped for reading. 57 * @throws Exception if an error occurs while processing a read completion. {@link #onFailed} 58 * will 59 * be called with the thrown exception set as the cause of the {@link CallbackException}. 60 */ onBodyChunkRead(UrlResponseInfo info, ByteBuffer bodyChunk)61 protected abstract void onBodyChunkRead(UrlResponseInfo info, ByteBuffer bodyChunk) 62 throws Exception; 63 64 /** 65 * Invoked when request is completed successfully. Once invoked, no other {@link 66 * UrlRequest.Callback} methods will be invoked. 67 * 68 * @param info Response information. 69 */ onSucceeded(UrlResponseInfo info)70 protected abstract void onSucceeded(UrlResponseInfo info); 71 72 /** 73 * Invoked if request failed for any reason after {@link UrlRequest#start}. Once invoked, no 74 * other 75 * {@link UrlRequest.Callback} methods will be invoked. {@code error} provides information about 76 * the failure. 77 * 78 * @param info Response information. May be {@code null} if no response was received. 79 * @param exception information about error. 80 */ onFailed(@ullable UrlResponseInfo info, CronetException exception)81 protected abstract void onFailed(@Nullable UrlResponseInfo info, CronetException exception); 82 83 /** 84 * Invoked if request was canceled via {@link UrlRequest#cancel}. Once invoked, no other {@link 85 * UrlRequest.Callback} methods will be invoked. 86 * 87 * @param info Response information. May be {@code null} if no response was received. 88 */ onCanceled(@ullable UrlResponseInfo info)89 protected abstract void onCanceled(@Nullable UrlResponseInfo info); 90 91 @Override onResponseStarted(UrlRequest request, UrlResponseInfo info)92 public final void onResponseStarted(UrlRequest request, UrlResponseInfo info) throws Exception { 93 onResponseStarted(info); 94 request.read(ByteBuffer.allocateDirect(BYTE_BUFFER_CAPACITY)); 95 } 96 97 @Override onRedirectReceived( UrlRequest request, UrlResponseInfo info, String newLocationUrl)98 public final void onRedirectReceived( 99 UrlRequest request, UrlResponseInfo info, String newLocationUrl) throws Exception { 100 if (shouldFollowRedirect(info, newLocationUrl)) { 101 request.followRedirect(); 102 } else { 103 request.cancel(); 104 } 105 } 106 107 @Override onReadCompleted( UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer)108 public final void onReadCompleted( 109 UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) throws Exception { 110 byteBuffer.flip(); 111 onBodyChunkRead(info, byteBuffer); 112 byteBuffer.clear(); 113 request.read(byteBuffer); 114 } 115 116 @Override onSucceeded(UrlRequest request, UrlResponseInfo info)117 public final void onSucceeded(UrlRequest request, UrlResponseInfo info) { 118 onSucceeded(info); 119 } 120 121 @Override onFailed(UrlRequest request, UrlResponseInfo info, CronetException error)122 public final void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) { 123 onFailed(info, error); 124 } 125 126 @Override onCanceled(UrlRequest request, UrlResponseInfo info)127 public final void onCanceled(UrlRequest request, UrlResponseInfo info) { 128 onCanceled(info); 129 } 130 } 131