@@ -163,6 +163,12 @@ int acquire_download_async_start(struct acquire_handle *handle, const char *url,
163163 CURL_SSLVERSION_TLSv1_2 );
164164
165165 be -> multi_handle = curl_multi_init ();
166+ if (!be -> multi_handle ) {
167+ acquire_handle_set_error (handle , ACQUIRE_ERROR_NETWORK_INIT_FAILED ,
168+ "curl_multi_init() failed" );
169+ cleanup_curl_backend (handle );
170+ return -1 ;
171+ }
166172 curl_multi_add_handle (be -> multi_handle , be -> easy_handle );
167173
168174 handle -> status = ACQUIRE_IN_PROGRESS ;
@@ -171,51 +177,55 @@ int acquire_download_async_start(struct acquire_handle *handle, const char *url,
171177
172178enum acquire_status acquire_download_async_poll (struct acquire_handle * handle ) {
173179 struct curl_backend * be ;
174- int still_running = 0 , r ;
175- CURLMsg * msg ;
176- if (!handle || !handle -> backend_handle )
180+ CURLMcode mc ;
181+ int still_running = 0 ;
182+
183+ /* 1. Basic sanity checks and state validation */
184+ if (handle == NULL )
177185 return ACQUIRE_ERROR ;
178186 if (handle -> status != ACQUIRE_IN_PROGRESS )
179187 return handle -> status ;
188+ if (handle -> backend_handle == NULL ) {
189+ acquire_handle_set_error (handle , ACQUIRE_ERROR_INVALID_ARGUMENT ,
190+ "Polling on an uninitialized backend." );
191+ return ACQUIRE_ERROR ;
192+ }
180193
181194 be = (struct curl_backend * )handle -> backend_handle ;
195+
196+ /* 2. Check for user cancellation first */
182197 if (handle -> cancel_flag ) {
183198 acquire_handle_set_error (handle , ACQUIRE_ERROR_CANCELLED ,
184- "Download cancelled by user" );
185- handle -> status = ACQUIRE_ERROR ;
199+ "Download cancelled by user." );
186200 cleanup_curl_backend (handle );
187- return handle -> status ;
201+ return ACQUIRE_ERROR ;
188202 }
189203
190- r = curl_multi_perform (be -> multi_handle , & still_running );
191- if (r != CURLM_OK ) {
204+ /* 3. Drive the multi stack to perform I/O */
205+ mc = curl_multi_perform (be -> multi_handle , & still_running );
206+ if (mc != CURLM_OK ) {
192207 acquire_handle_set_error (handle , ACQUIRE_ERROR_NETWORK_FAILURE ,
193208 "curl_multi_perform() failed: %s" ,
194- curl_multi_strerror (r ));
209+ curl_multi_strerror (mc ));
195210 cleanup_curl_backend (handle );
196- return handle -> status ;
211+ return ACQUIRE_ERROR ;
197212 }
198- if (still_running == 0 ) {
199- int queued ;
200- msg = curl_multi_info_read (be -> multi_handle , & queued );
201- if (msg ) {
202- if (msg -> msg == CURLMSG_DONE ) {
203- long response_code = 0 ;
204213
205- /* First, check if the transfer was successful */
214+ /* 4. Check for transfer completion messages */
215+ {
216+ CURLMsg * msg ;
217+ int msgs_left ;
218+ while ((msg = curl_multi_info_read (be -> multi_handle , & msgs_left ))) {
219+ if (msg -> msg == CURLMSG_DONE ) {
220+ /* This transfer is finished. Since we only manage one, the whole
221+ * operation is done. */
206222 if (msg -> data .result == CURLE_OK ) {
207- curl_off_t cl ;
208223 handle -> status = ACQUIRE_COMPLETE ;
209- /* Explicitly get final size to ensure it's set */
210- if (curl_easy_getinfo (msg -> easy_handle ,
211- CURLINFO_CONTENT_LENGTH_DOWNLOAD_T ,
212- & cl ) == CURLE_OK &&
213- cl >= 0 ) {
214- handle -> total_size = (off_t )cl ;
215- }
216224 } else {
225+ long response_code = 0 ;
217226 curl_easy_getinfo (msg -> easy_handle , CURLINFO_RESPONSE_CODE ,
218227 & response_code );
228+
219229 if (msg -> data .result == CURLE_COULDNT_RESOLVE_HOST ) {
220230 acquire_handle_set_error (handle , ACQUIRE_ERROR_HOST_NOT_FOUND ,
221231 "Could not resolve host: %s" ,
@@ -229,22 +239,21 @@ enum acquire_status acquire_download_async_poll(struct acquire_handle *handle) {
229239 curl_easy_strerror (msg -> data .result ));
230240 }
231241 }
242+ break ; /* Exit loop, we only care about our one transfer */
232243 }
233- } else {
234- /* If still_running is 0 but we have no message, it implies success. */
235- if (handle -> status == ACQUIRE_IN_PROGRESS ) {
236- curl_off_t cl ;
237- handle -> status = ACQUIRE_COMPLETE ;
238- if (curl_easy_getinfo (be -> easy_handle ,
239- CURLINFO_CONTENT_LENGTH_DOWNLOAD_T ,
240- & cl ) == CURLE_OK &&
241- cl >= 0 ) {
242- handle -> total_size = (off_t )cl ;
243- }
244- }
244+ }
245+ }
246+
247+ /* 5. If it's not running, the operation is over */
248+ if (still_running == 0 ) {
249+ if (handle -> status == ACQUIRE_IN_PROGRESS ) {
250+ /* If curl reports not running but we haven't received a DONE message,
251+ * it implies success. */
252+ handle -> status = ACQUIRE_COMPLETE ;
245253 }
246254 cleanup_curl_backend (handle );
247255 }
256+
248257 return handle -> status ;
249258}
250259
0 commit comments