• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 package com.google.fcp.client.http;
15 
16 import com.google.errorprone.annotations.concurrent.GuardedBy;
17 import java.io.Closeable;
18 
19 /**
20  * A base class for building a Java/JNI-based implementation of the C++ {@code HttpClient}
21  * interface.
22  *
23  * <p>This class is defined in conjunction with the {@code java_http_client.cc/h} C++ code that
24  * invokes it via JNI.
25  *
26  * <p>A note on thread safety:
27  *
28  * <ol>
29  *   <li>Incoming calls from the native layer can generally come from any thread, and hence
30  *       implementations of these classes must be thread safe.
31  *   <li>Outgoing calls to the native layer (e.g. {@link #readRequestBody}, {@link
32  *       #onResponseStarted}, etc.) may also be made from any thread, but for a single {@link
33  *       HttpRequestHandle} there must never be any concurrent outgoing calls from more than one
34  *       thread (hence they are {@code @GuardedBy("this")}).
35  *   <li>Outgoing calls to the native layer must only be made once an {@link #performRequests} has
36  *       been called on a given {@link HttpRequestHandle}, and not before.
37  * </ol>
38  */
39 public abstract class HttpClientForNative implements Closeable {
40   /**
41    * A base class for building a Java/JNI-based implementation of the C++ {@code HttpRequestHandle}
42    * and related interfaces.
43    *
44    * <p>This class is defined in conjunction with the {@code java_http_client.cc/h} C++ code that
45    * invokes it via JNI.
46    */
47   public abstract static class HttpRequestHandle implements Closeable {
48     /**
49      * Called by the native layer to get the request's latest total sent/received bytes stats. May
50      * be called multiple times, and from any thread.
51      *
52      * <p>See C++'s {@code HttpRequestHandle::TotalSentReceivedBytes}.
53      *
54      * @return a serialized {@link JniHttpSentReceivedBytes} proto.
55      */
getTotalSentReceivedBytes()56     public abstract byte[] getTotalSentReceivedBytes();
57 
58     /**
59      * Called by the native layer when the request isn't needed anymore. May be called multiple
60      * times, and from any thread.
61      */
62     @Override
close()63     public abstract void close();
64 
65     /**
66      * Reads up to {@code requestedBytes} of request body data into {@code buffer}, via the native
67      * layer. If the end of the data is reached, then -1 will be placed in the mutable
68      * single-element {@code actualBytesRead} array (this corresponds to C++'s {@code
69      * HttpRequest::ReadBody} returning {@code OUT_OF_RANGE}). Otherwise, at least 1 byte of data
70      * will have been read, and the actual amount of bytes that were read will be placed in the
71      * {@code actualBytesRead} array.
72      *
73      * <p>If the return value is false, then {@link HttpClientForNative} implementation must not
74      * call {@link #onResponseError} anymore, as the native layer will already have called the
75      * corresponding C++ callback.
76      *
77      * <p>See C++'s {@code HttpRequest::ReadBody}.
78      *
79      * <p>Must only be called <strong>after</strong> {@link #performRequests} is called on this
80      * handle. Only one of the callback methods on this handle may be called at any given time (but
81      * they may be called from any thread).
82      *
83      * @return true if the read succeeded (incl. if the end of data was reached), false if the read
84      *     failed (in which case the request should be aborted without calling any more callback
85      *     methods).
86      */
87     // Note: can be overridden in unit tests, to intercept/mock out calls to the native layer.
88     @GuardedBy("this")
readRequestBody(byte[] buffer, long requestedBytes, int[] actualBytesRead)89     protected boolean readRequestBody(byte[] buffer, long requestedBytes, int[] actualBytesRead) {
90       return HttpClientForNative.readRequestBody(
91           nativeHandle, buffer, requestedBytes, actualBytesRead);
92     }
93 
94     /**
95      * Signals to the native layer that the response headers (provided as a serialized {@link
96      * JniHttpResponse}) have been received.
97      *
98      * <p>See C++'s {@code HttpRequestCallback::OnResponseStarted}.
99      *
100      * <p>Must only be called <strong>after</strong> {@link #performRequests} is called on this
101      * handle. Only one of the callback methods on this handle may be called at any given time (but
102      * they may be called from any thread).
103      *
104      * @return true if the response headers were successfully processed, false if not (in which case
105      *     the request should be aborted without calling any more callback methods).
106      */
107     // Note: can be overridden in unit tests, to intercept/mock out calls to the native layer.
108     @GuardedBy("this")
onResponseStarted(byte[] responseProto)109     protected boolean onResponseStarted(byte[] responseProto) {
110       return HttpClientForNative.onResponseStarted(nativeHandle, responseProto);
111     }
112 
113     /**
114      * Signals to the native layer that an error (provided as a serialized {@link
115      * com.google.rpc.Status} proto) occurred before the response headers were received.
116      *
117      * <p>See C++'s {@code HttpRequestCallback::OnResponseError}.
118      *
119      * <p>Must only be called <strong>after</strong> {@link #performRequests} is called on this
120      * handle. Only one of the callback methods on this handle may be called at any given time (but
121      * they may be called from any thread).
122      */
123     // Note: can be overridden in unit tests, to intercept/mock out calls to the native layer.
124     @GuardedBy("this")
onResponseError(byte[] statusProto)125     protected void onResponseError(byte[] statusProto) {
126       HttpClientForNative.onResponseError(nativeHandle, statusProto);
127     }
128 
129     /**
130      * Provides {@code bytesAvailable} bytes of the response body to the native layer, via {@code
131      * data}.
132      *
133      * <p>See C++'s {@code HttpRequestCallback::OnResponseBody}.
134      *
135      * <p>Must only be called <strong>after</strong> {@link #performRequests} is called on this
136      * handle. Only one of the callback methods on this handle may be called at any given time (but
137      * they may be called from any thread).
138      *
139      * @return true if the data was successfully processed, or false if not (in which case the
140      *     request should be aborted without calling any more callback methods).
141      */
142     // Note: can be overridden in unit tests, to intercept/mock out calls to the native layer.
143     @GuardedBy("this")
onResponseBody(byte[] data, int bytesAvailable)144     protected boolean onResponseBody(byte[] data, int bytesAvailable) {
145       return HttpClientForNative.onResponseBody(nativeHandle, data, bytesAvailable);
146     }
147 
148     /**
149      * Signals to the native layer that an error (provided as a serialized {@link
150      * com.google.rpc.Status} proto) occurred while reading the response body.
151      *
152      * <p>See C++'s {@code HttpRequestCallback::OnResponseBodyError}.
153      *
154      * <p>Must only be called <strong>after</strong> {@link #performRequests} is called on this
155      * handle. Only one of the callback methods on this handle may be called at any given time (but
156      * they may be called from any thread).
157      */
158     // Note: can be overridden in unit tests, to intercept/mock out calls to the native layer.
159     @GuardedBy("this")
onResponseBodyError(byte[] statusProto)160     protected void onResponseBodyError(byte[] statusProto) {
161       HttpClientForNative.onResponseBodyError(nativeHandle, statusProto);
162     }
163 
164     /**
165      * Signals to the native layer that the request completed successfully.
166      *
167      * <p>See C++'s {@code HttpRequestCallback::OnResponseBodyCompleted}.
168      *
169      * <p>Must only be called <strong>after</strong> {@link #performRequests} is called on this
170      * handle. Only one of the callback methods on this handle may be called at any given time (but
171      * they may be called from any thread).
172      */
173     // Note: can be overridden in unit tests, to intercept/mock out calls to the native layer.
174     @GuardedBy("this")
onResponseCompleted()175     protected void onResponseCompleted() {
176       HttpClientForNative.onResponseCompleted(nativeHandle);
177     }
178 
179     /**
180      * A field that native code uses to associate a native pointer with this object. This field must
181      * never be modified by Java code.
182      */
183     // Note: this field is volatile to ensure that if it is read from a different thread than the
184     // one that wrote to it earlier, the second thread will see the updated value.
185     private volatile long nativeHandle = 0;
186   }
187 
188   /**
189    * Creates an {@link HttpRequestHandle} for use with {@link #performRequests}.
190    *
191    * <p>May be called from any thread.
192    *
193    * @param requestProto a serialized {@link JniHttpRequest} proto.
194    */
enqueueRequest(byte[] requestProto)195   public abstract HttpRequestHandle enqueueRequest(byte[] requestProto);
196 
197   /**
198    * Performs the requests corresponding to the given objects, which must be {@link
199    * HttpRequestHandle} instances previously returned by {@link #enqueueRequest}.
200    *
201    * <p>May be called from any thread.
202    *
203    * @return a serialized {@link com.google.rpc.Status} proto indicating success or failure.
204    */
205   // NOTE: The parameter type is an 'Object[]' array, because this makes it easier for the native
206   // code calling this over JNI to construct the array (it can simply look up the 'Object') class.
207   // The Java implementation is expected to downcast the objects in the array to its RequestHandle
208   // implementation class.
performRequests(Object[] requests)209   public abstract byte[] performRequests(Object[] requests);
210 
211   /**
212    * Called by native when the client is no longer used and all resources can be released. May be
213    * called multiple times, and from any thread.
214    */
215   @Override
close()216   public abstract void close();
217 
218   // The actual native callback methods, which the HttpRequestHandle class provides wrappers for.
219   // See that class's docs for more info.
readRequestBody( long nativeRequestHandle, byte[] buffer, long requestedBytes, int[] actualBytesRead)220   private static native boolean readRequestBody(
221       long nativeRequestHandle, byte[] buffer, long requestedBytes, int[] actualBytesRead);
222 
onResponseStarted(long nativeRequestHandle, byte[] responseProto)223   private static native boolean onResponseStarted(long nativeRequestHandle, byte[] responseProto);
224 
onResponseError(long nativeRequestHandle, byte[] statusProto)225   private static native void onResponseError(long nativeRequestHandle, byte[] statusProto);
226 
onResponseBody( long nativeRequestHandle, byte[] data, int bytesAvailable)227   private static native boolean onResponseBody(
228       long nativeRequestHandle, byte[] data, int bytesAvailable);
229 
onResponseBodyError(long nativeRequestHandle, byte[] statusProto)230   private static native void onResponseBodyError(long nativeRequestHandle, byte[] statusProto);
231 
onResponseCompleted(long nativeRequestHandle)232   private static native void onResponseCompleted(long nativeRequestHandle);
233 }
234