@@ -41,22 +41,58 @@ protected HttpClientConnection(long connectionBinding) {
4141 */
4242 public HttpStream makeRequest (HttpRequest request , HttpStreamResponseHandler streamHandler )
4343 throws CrtRuntimeException {
44+ return makeRequest (request , streamHandler , false );
45+ }
46+
47+ /**
48+ * Schedules an HttpRequest on the Native EventLoop for this HttpClientConnection specific to HTTP/1.1 connection.
49+ *
50+ * @param request The Request to make to the Server.
51+ * @param streamHandler The Stream Handler to be called from the Native EventLoop
52+ * @param useManualDataWrites When {@code true}, request body data is provided via
53+ * {@link HttpStreamBase#writeData} instead of from the request's
54+ * {@link HttpRequestBodyStream}.
55+ *
56+ * <p>By design, CRT does not support setting both a body stream and enabling
57+ * manual writes for HTTP/1.1. Body streams are intended for requests whose
58+ * payload is available in full at the time of sending. If the stream does not
59+ * signal end-of-stream promptly, the event loop will busy-wait (hot-loop) for
60+ * more data, wasting CPU time. Manual writes avoid this by letting the caller
61+ * control when data is sent; the event loop only processes the request when
62+ * {@link HttpStreamBase#writeData} is called and is free to service other
63+ * requests in the meantime.
64+ *
65+ * <p>If the request was created with an {@link HttpRequestBodyStream} and this
66+ * parameter is {@code true}, an {@link IllegalStateException} is thrown
67+ * immediately.
68+ * @throws CrtRuntimeException if stream creation fails
69+ * @return The HttpStream that represents this Request/Response Pair. It can be closed at any time during the
70+ * request/response, but must be closed by the user thread making this request when it's done.
71+ */
72+ public HttpStream makeRequest (HttpRequest request , HttpStreamResponseHandler streamHandler ,
73+ boolean useManualDataWrites ) throws CrtRuntimeException , IllegalStateException {
4474 if (isNull ()) {
4575 throw new IllegalStateException ("HttpClientConnection has been closed, can't make requests on it." );
4676 }
4777 if (getVersion () == HttpVersion .HTTP_2 ) {
4878 throw new IllegalArgumentException ("HTTP/1 only method called on an HTTP/2 connection." );
4979 }
80+ if (useManualDataWrites && request .getBodyStream () != null ) {
81+ throw new IllegalStateException (
82+ "Cannot use manual data writes with a body stream on an HTTP/1.1 request. "
83+ + "Either remove the body stream or set useManualDataWrites to false." );
84+ }
5085 HttpStreamBase stream = httpClientConnectionMakeRequest (getNativeHandle (),
5186 request .marshalForJni (),
5287 request .getBodyStream (),
53- new HttpStreamResponseHandlerNativeAdapter (streamHandler ));
88+ new HttpStreamResponseHandlerNativeAdapter (streamHandler ),
89+ useManualDataWrites );
5490
5591 return (HttpStream )stream ;
5692 }
5793
5894 /**
59- * Schedules an HttpRequestBase on the Native EventLoop for this HttpClientConnection applies to both HTTP/2 and HTTP/1.1 connection .
95+ * Schedules an HttpRequestBase on the Native EventLoop for this HttpClientConnection. Applies to both HTTP/2 and HTTP/1.1 connections .
6096 *
6197 * @param request The Request to make to the Server.
6298 * @param streamHandler The Stream Handler to be called from the Native EventLoop
@@ -65,13 +101,30 @@ public HttpStream makeRequest(HttpRequest request, HttpStreamResponseHandler str
65101 * request/response, but must be closed by the user thread making this request when it's done.
66102 */
67103 public HttpStreamBase makeRequest (HttpRequestBase request , HttpStreamBaseResponseHandler streamHandler ) throws CrtRuntimeException {
104+ return makeRequest (request , streamHandler , false );
105+ }
106+
107+ /**
108+ * Schedules an HttpRequestBase on the Native EventLoop for this HttpClientConnection. Applies to both HTTP/2 and HTTP/1.1 connections.
109+ *
110+ * @param request The Request to make to the Server.
111+ * @param streamHandler The Stream Handler to be called from the Native EventLoop
112+ * @param useManualDataWrites When true, request body data will be provided via
113+ * {@link HttpStreamBase#writeData} instead of from the request's body stream.
114+ * @throws CrtRuntimeException if stream creation fails
115+ * @return The HttpStream that represents this Request/Response Pair. It can be closed at any time during the
116+ * request/response, but must be closed by the user thread making this request when it's done.
117+ */
118+ public HttpStreamBase makeRequest (HttpRequestBase request , HttpStreamBaseResponseHandler streamHandler ,
119+ boolean useManualDataWrites ) throws CrtRuntimeException {
68120 if (isNull ()) {
69121 throw new IllegalStateException ("HttpClientConnection has been closed, can't make requests on it." );
70122 }
71123 HttpStreamBase stream = httpClientConnectionMakeRequest (getNativeHandle (),
72124 request .marshalForJni (),
73125 request .getBodyStream (),
74- new HttpStreamResponseHandlerNativeAdapter (streamHandler ));
126+ new HttpStreamResponseHandlerNativeAdapter (streamHandler ),
127+ useManualDataWrites );
75128
76129 return stream ;
77130 }
@@ -172,7 +225,8 @@ public static boolean isErrorRetryable(HttpException exception) {
172225 private static native HttpStreamBase httpClientConnectionMakeRequest (long connectionBinding ,
173226 byte [] marshalledRequest ,
174227 HttpRequestBodyStream bodyStream ,
175- HttpStreamResponseHandlerNativeAdapter responseHandler ) throws CrtRuntimeException ;
228+ HttpStreamResponseHandlerNativeAdapter responseHandler ,
229+ boolean useManualDataWrites ) throws CrtRuntimeException ;
176230
177231 private static native void httpClientConnectionShutdown (long connectionBinding ) throws CrtRuntimeException ;
178232 private static native boolean httpClientConnectionIsOpen (long connectionBinding ) throws CrtRuntimeException ;
0 commit comments