@@ -186,7 +186,7 @@ processed automatically when making the requests::
186186 'body' => ['parameter1' => 'value1', '...'], 
187187
188188 // using a closure to generate the uploaded data 
189-  'body' => function ()  { 
189+  'body' => function (int $size): string  { 
190190 // ... 
191191 }, 
192192
@@ -199,12 +199,39 @@ When uploading data with the ``POST`` method, if you don't define the
199199form data and adds the required
200200``'Content-Type: application/x-www-form-urlencoded' `` header for you.
201201
202- When uploading JSON payloads, use  the ``json `` option instead of `` body ``. The 
203- given content will be JSON-encoded automatically and  the request will add  the
204- `` Content-Type: application/json `` automatically too:: 
202+ When the ``body `` option is set as a closure, it will be called several times until 
203+ it returns the empty string, which signals  the end of the body. Each time,  the
204+ closure should return a string smaller than the amount requested as argument. 
205205
206-  $response = $httpClient->request('POST', 'https://...', [ 
207-  'json' => ['param1' => 'value1', '...'], 
206+ A generator or any ``Traversable `` can also be used instead of a closure.
207+ 
208+ .. tip ::
209+ 
210+  When uploading JSON payloads, use the ``json `` option instead of ``body ``. The
211+  given content will be JSON-encoded automatically and the request will add the
212+  ``Content-Type: application/json `` automatically too::
213+ 
214+  $response = $httpClient->request('POST', 'https://...', [ 
215+  'json' => ['param1' => 'value1', '...'], 
216+  ]); 
217+ 
218+  $decodedPayload = $response->toArray(); 
219+ 
220+ To submit a form with file uploads, it is your responsibility to encode the body
221+ according to the ``multipart/form-data `` content-type. The
222+ :doc: `Symfony Mime  </components/mime >` component makes it a few lines of code::
223+ 
224+  use Symfony\Component\Mime\Part\DataPart; 
225+  use Symfony\Component\Mime\Part\Multipart\FormDataPart; 
226+ 
227+  $formFields = [ 
228+  'regular_field' => 'some value', 
229+  'file_field' => DataPart::fromPath('/path/to/uploaded/file'), 
230+  ]; 
231+  $formData = new FormDataPart($formFields); 
232+  $client->request('POST', 'https://...', [ 
233+  'headers' => $formData->getPreparedHeaders()->toArray(), 
234+  'body' => $formData->bodyToIterable(), 
208235 ]); 
209236
210237Cookies
@@ -232,12 +259,47 @@ making a request. Use the ``max_redirects`` setting to configure this behavior
232259 'max_redirects' => 0, 
233260 ]); 
234261
262+ HTTP Proxies
263+ ~~~~~~~~~~~~ 
264+ 
265+ By default, this component honors the standard environment variables that your
266+ Operating System defines to direct the HTTP traffic through your local proxy.
267+ This means there is usually nothing to configure to have the client work with
268+ proxies, provided these env vars are properly configured.
269+ 
270+ You can still set or override these settings using the ``proxy `` and ``no_proxy ``
271+ options:
272+ 
273+ * ``proxy `` should be set to the ``http://... `` URL of the proxy to get through
274+ 
275+ * ``no_proxy `` disables the proxy for a comma-separated list of hosts that do not
276+  require it to get reached.
277+ 
278+ Progress Callback
279+ ~~~~~~~~~~~~~~~~~ 
280+ 
281+ By providing a callable to the ``on_progress `` option, one can track
282+ uploads/downloads as they complete. This callback is guaranteed to be called on
283+ DNS resolution, on arrival of headers and on completion; additionally it is
284+ called when new data is uploaded or downloaded and at least once per second::
285+ 
286+  $response = $httpClient->request('GET', 'https://...', [ 
287+  'on_progress' => function (int $dlNow, int $dlSize, array $info): void { 
288+  // $dlNow is the number of bytes downloaded so far 
289+  // $dlSize is the total size to be downloaded or -1 if it is unknown 
290+  // $info is what $response->getInfo() would return at this very time 
291+  }, 
292+  ]; 
293+ 
294+ Any exceptions thrown from the callback will be wrapped in an instance of
295+ ``TransportExceptionInterface `` and will abort the request.
296+ 
235297Advanced Options
236298~~~~~~~~~~~~~~~~ 
237299
238300The :class: `Symfony\\ Contracts\\ HttpClient\\ HttpClientInterface ` defines all the
239301options you might need to take full control of the way the request is performed,
240- including progress monitoring,  DNS pre-resolution, timeout,  SSL parameters, etc.
302+ including DNS pre-resolution, SSL parameters, public key pinning , etc.
241303
242304Processing Responses
243305-------------------- 
@@ -257,6 +319,9 @@ following methods::
257319 // gets the response body as a string 
258320 $content = $response->getContent(); 
259321
322+  // cancels the request/response 
323+  $response->cancel(); 
324+ 
260325 // returns info coming from the transport layer, such as "response_headers", 
261326 // "redirect_count", "start_time", "redirect_url", etc. 
262327 $httpInfo = $response->getInfo(); 
@@ -285,10 +350,6 @@ response sequentially instead of waiting for the entire response::
285350 $response = $httpClient->request('GET', $url, [ 
286351 // optional: if you don't want to buffer the response in memory 
287352 'buffer' => false, 
288-  // optional: to display details about the response progress 
289-  'on_progress' => function (int $dlNow, int $dlSize, array $info): void { 
290-  // ... 
291-  }, 
292353 ]); 
293354
294355 // Responses are lazy: this code is executed as soon as headers are received 
@@ -303,6 +364,28 @@ response sequentially instead of waiting for the entire response::
303364 fwrite($fileHandler, $chunk->getContent()); 
304365 } 
305366
367+ Canceling Responses
368+ ~~~~~~~~~~~~~~~~~~~ 
369+ 
370+ To abort a request (e.g. because it didn't complete in due time, or you want to
371+ fetch only the first bytes of the response, etc.), you can either use the
372+ ``cancel() `` method of ``ResponseInterface ``::
373+ 
374+  $response->cancel() 
375+ 
376+ Or throw an exception from a progress callback::
377+ 
378+  $response = $client->request('GET', 'https://...', [ 
379+  'on_progress' => function (int $dlNow, int $dlSize, array $info): void { 
380+  // ... 
381+ 
382+  throw new \MyException(); 
383+  }, 
384+  ]); 
385+ 
386+ The exception will be wrapped in an instance of ``TransportExceptionInterface ``
387+ and will abort the request.
388+ 
306389Handling Exceptions
307390~~~~~~~~~~~~~~~~~~~ 
308391
@@ -529,7 +612,7 @@ PSR-18 Compatibility
529612-------------------- 
530613
531614This component uses and implements abstractions defined by the
532- ``symfony/contracts `` package . It also implements the `PSR-18 `_ (HTTP Client)
615+ ``symfony/http-client- contracts ``. It also implements the `PSR-18 `_ (HTTP Client)
533616specifications via the :class: `Symfony\\ Component\\ HttpClient\\ Psr18Client `
534617class, which is an adapter to turn a Symfony ``HttpClientInterface `` into a
535618PSR-18 ``ClientInterface ``.
0 commit comments