57
57
* @package WordPress
58
58
* @subpackage Async_HTTP
59
59
*/
60
- class Client {
60
+ class Client implements ClientInterface {
61
61
62
62
/**
63
63
* The maximum number of concurrent connections allowed.
@@ -71,16 +71,6 @@ class Client {
71
71
*/
72
72
protected $ concurrency ;
73
73
74
- /**
75
- * The maximum number of redirects to follow for a single request.
76
- *
77
- * This prevents infinite redirect loops and provides a degree of control over the client's behavior.
78
- * Setting it too high might lead to unexpected navigation paths.
79
- *
80
- * @var int
81
- */
82
- protected $ max_redirects = 3 ;
83
-
84
74
/**
85
75
* All the HTTP requests ever enqueued with this Client.
86
76
*
@@ -112,34 +102,35 @@ class Client {
112
102
protected $ requests_started_at = array ();
113
103
114
104
public function __construct ( $ options = array () ) {
115
- $ this ->concurrency = $ options ['concurrency ' ] ?? 10 ;
116
- $ this ->max_redirects = $ options ['max_redirects ' ] ?? 3 ;
105
+ $ this ->concurrency = $ options ['concurrency ' ] ?? 10 ;
117
106
$ this ->request_timeout_ms = $ options ['timeout_ms ' ] ?? 30000 ;
118
- $ this ->requests = array ();
107
+ $ this ->requests = array ();
119
108
}
120
109
121
110
/**
122
111
* Returns a RemoteFileReader that streams the response body of the
123
112
* given request.
124
113
*
125
114
* @param Request $request The request to stream.
115
+ * @param array $options Options for the request.
126
116
*
127
117
* @return RequestReadStream
128
118
*/
129
- public function fetch ( $ request , $ options = array () ) {
119
+ public function fetch ( Request $ request , array $ options = [] ) {
130
120
return new RequestReadStream ( $ request ,
131
- array_merge ( [ 'client ' => $ this ], is_array ( $ options ) ? $ options : iterator_to_array ( $ options ) ) );
121
+ array_merge ( [ 'client ' => $ this ], $ options ) );
132
122
}
133
123
134
124
/**
135
125
* Returns an array of RemoteFileReader instances that stream the response bodies
136
126
* of the given requests.
137
127
*
138
128
* @param Request[] $requests The requests to stream.
129
+ * @param array $options Options for the requests.
139
130
*
140
131
* @return RequestReadStream[]
141
132
*/
142
- public function fetch_many ( array $ requests , $ options = array () ) {
133
+ public function fetch_many ( array $ requests , array $ options = [] ) {
143
134
$ streams = array ();
144
135
145
136
foreach ( $ requests as $ request ) {
@@ -155,11 +146,11 @@ public function fetch_many( array $requests, $options = array() ) {
155
146
* an internal queue. Network transmission is delayed until one of the returned
156
147
* streams is read from.
157
148
*
158
- * @param Request|Request [] $requests The HTTP request(s) to enqueue. Can be a single request or an array of requests .
149
+ * @param Request[] $requests The HTTP request(s) to enqueue.
159
150
*/
160
151
public function enqueue ( $ requests ) {
161
- if ( ! is_array ( $ requests ) ) {
162
- $ requests = array ( $ requests ) ;
152
+ if (! is_array ($ requests) ) {
153
+ $ requests = [ $ requests] ;
163
154
}
164
155
165
156
foreach ( $ requests as $ request ) {
@@ -199,7 +190,6 @@ public function enqueue( $requests ) {
199
190
*
200
191
* * `Client::EVENT_GOT_HEADERS`
201
192
* * `Client::EVENT_BODY_CHUNK_AVAILABLE`
202
- * * `Client::EVENT_REDIRECT`
203
193
* * `Client::EVENT_FAILED`
204
194
* * `Client::EVENT_FINISHED`
205
195
*
@@ -227,7 +217,7 @@ public function enqueue( $requests ) {
227
217
* $request = new Request( "https://w.org" );
228
218
*
229
219
* $client = new HttpClientClient();
230
- * $client->enqueue( $request );
220
+ * $client->enqueue( [ $request] );
231
221
* $event = $client->await_next_event( [
232
222
* 'request_id' => $request->id,
233
223
* ] );
@@ -239,15 +229,14 @@ public function enqueue( $requests ) {
239
229
* request #1 has finished before you started awaiting
240
230
* events for request #2.
241
231
*
242
- * @param $query
232
+ * @param array $query Query parameters for filtering events.
243
233
*
244
234
* @return bool
245
235
*/
246
- public function await_next_event ( $ query = array () ) {
236
+ public function await_next_event ( array $ query = [] ) {
247
237
$ ordered_events = array (
248
238
self ::EVENT_GOT_HEADERS ,
249
239
self ::EVENT_BODY_CHUNK_AVAILABLE ,
250
- self ::EVENT_REDIRECT ,
251
240
self ::EVENT_FAILED ,
252
241
self ::EVENT_FINISHED ,
253
242
);
@@ -269,10 +258,6 @@ public function await_next_event( $query = array() ) {
269
258
$ events = array ();
270
259
foreach ( $ query ['requests ' ] as $ query_request ) {
271
260
$ events [] = $ query_request ->id ;
272
- while ( $ query_request ->redirected_to ) {
273
- $ query_request = $ query_request ->redirected_to ;
274
- $ events [] = $ query_request ->id ;
275
- }
276
261
}
277
262
}
278
263
@@ -308,7 +293,7 @@ public function await_next_event( $query = array() ) {
308
293
return false ;
309
294
}
310
295
311
- public function has_pending_event ( $ request , $ event_type ) {
296
+ public function has_pending_event ( Request $ request , string $ event_type ): bool {
312
297
return $ this ->events [ $ request ->id ][ $ event_type ] ?? false ;
313
298
}
314
299
@@ -403,7 +388,11 @@ protected function event_loop_tick() {
403
388
$ this ->get_active_requests ( Request::STATE_RECEIVING_HEADERS )
404
389
);
405
390
406
- $ this ->handle_redirects (
391
+ $ this ->receive_response_body (
392
+ $ this ->get_active_requests ( Request::STATE_RECEIVING_BODY )
393
+ );
394
+
395
+ $ this ->mark_requests_finished (
407
396
$ this ->get_active_requests ( Request::STATE_RECEIVED )
408
397
);
409
398
@@ -427,11 +416,6 @@ protected function event_loop_tick() {
427
416
return true ;
428
417
}
429
418
430
- $ this ->receive_response_body (
431
- $ this ->get_active_requests ( Request::STATE_RECEIVING_BODY )
432
- );
433
-
434
-
435
419
return true ;
436
420
}
437
421
@@ -779,8 +763,6 @@ protected function receive_response_headers( $requests ) {
779
763
}
780
764
781
765
/**
782
- * Reads the next received portion of HTTP response headers for multiple requests.
783
- *
784
766
* @param array $requests An array of requests.
785
767
*/
786
768
protected function receive_response_body ( $ requests ) {
@@ -807,60 +789,6 @@ protected function receive_response_body( $requests ) {
807
789
}
808
790
}
809
791
810
- /**
811
- * @param array $requests An array of requests.
812
- */
813
- protected function handle_redirects ( $ requests ) {
814
- foreach ( $ requests as $ request ) {
815
- $ response = $ request ->response ;
816
- if ( ! $ response ) {
817
- continue ;
818
- }
819
- $ code = $ response ->status_code ;
820
- $ this ->mark_finished ( $ request );
821
- if ( ! ( $ code >= 300 && $ code < 400 ) ) {
822
- continue ;
823
- }
824
-
825
- $ location = $ response ->get_header ( 'location ' );
826
- if ( null === $ location ) {
827
- continue ;
828
- }
829
-
830
- $ redirects_so_far = 0 ;
831
- $ cause = $ request ;
832
- while ( $ cause ->redirected_from ) {
833
- ++ $ redirects_so_far ;
834
- $ cause = $ cause ->redirected_from ;
835
- }
836
-
837
- if ( $ redirects_so_far >= $ this ->max_redirects ) {
838
- $ this ->set_error ( $ request , new HttpError ( 'Too many redirects ' ) );
839
- continue ;
840
- }
841
-
842
- $ redirect_url = $ location ;
843
- $ parsed = WPURL ::parse ($ redirect_url , $ request ->url );
844
- if (false === $ parsed ) {
845
- $ this ->set_error ( $ request , new HttpError ( sprintf ( 'Invalid redirect URL: %s ' , $ redirect_url ) ) );
846
- continue ;
847
- }
848
- $ redirect_url = $ parsed ->toString ();
849
-
850
- $ this ->events [ $ request ->id ][ self ::EVENT_REDIRECT ] = true ;
851
- $ this ->enqueue (
852
- new Request (
853
- $ redirect_url ,
854
- array (
855
- // Redirects are always GET requests
856
- 'method ' => 'GET ' ,
857
- 'redirected_from ' => $ request ,
858
- )
859
- )
860
- );
861
- }
862
- }
863
-
864
792
/**
865
793
* Parses an HTTP headers string into an array containing the status and headers.
866
794
*
@@ -1082,7 +1010,6 @@ protected function stream_select( $requests, $mode ) {
1082
1010
1083
1011
const EVENT_GOT_HEADERS = 'EVENT_GOT_HEADERS ' ;
1084
1012
const EVENT_BODY_CHUNK_AVAILABLE = 'EVENT_BODY_CHUNK_AVAILABLE ' ;
1085
- const EVENT_REDIRECT = 'EVENT_REDIRECT ' ;
1086
1013
const EVENT_FAILED = 'EVENT_FAILED ' ;
1087
1014
const EVENT_FINISHED = 'EVENT_FINISHED ' ;
1088
1015
@@ -1097,4 +1024,10 @@ protected function stream_select( $requests, $mode ) {
1097
1024
* 5/100th of a second
1098
1025
*/
1099
1026
const NONBLOCKING_TIMEOUT_MICROSECONDS = 0.05 * self ::MICROSECONDS_TO_SECONDS ;
1027
+
1028
+ protected function mark_requests_finished ( $ requests ) {
1029
+ foreach ( $ requests as $ request ) {
1030
+ $ this ->mark_finished ( $ request );
1031
+ }
1032
+ }
1100
1033
}
0 commit comments