2
namespace GuzzleHttp\Subscriber;
4
use GuzzleHttp\Event\BeforeEvent;
5
use GuzzleHttp\Event\RequestEvents;
6
use GuzzleHttp\Event\SubscriberInterface;
7
use GuzzleHttp\Message\AppliesHeadersInterface;
8
use GuzzleHttp\Message\RequestInterface;
9
use GuzzleHttp\Mimetypes;
10
use GuzzleHttp\Stream\StreamInterface;
13
* Prepares requests with a body before sending
17
* - expect: Set to true to enable the "Expect: 100-Continue" header for a
18
* request that send a body. Set to false to disable "Expect: 100-Continue".
19
* Set to a number so that the size of the payload must be greater than the
20
* number in order to send the Expect header. Setting to a number will send
21
* the Expect header for all requests in which the size of the payload cannot
22
* be determined or where the body is not rewindable.
24
class Prepare implements SubscriberInterface
26
public function getEvents()
28
return ['before' => ['onBefore', RequestEvents::PREPARE_REQUEST]];
31
public function onBefore(BeforeEvent $event)
33
$request = $event->getRequest();
35
// Set the appropriate Content-Type for a request if one is not set and
36
// there are form fields
37
if (!($body = $request->getBody())) {
41
$this->addContentLength($request, $body);
43
if ($body instanceof AppliesHeadersInterface) {
44
// Synchronize the body with the request headers
45
$body->applyRequestHeaders($request);
46
} elseif (!$request->hasHeader('Content-Type')) {
47
$this->addContentType($request, $body);
50
$this->addExpectHeader($request, $body);
53
private function addContentType(
54
RequestInterface $request,
57
if (!($uri = $body->getMetadata('uri'))) {
61
// Guess the content-type based on the stream's "uri" metadata value.
62
// The file extension is used to determine the appropriate mime-type.
63
if ($contentType = Mimetypes::getInstance()->fromFilename($uri)) {
64
$request->setHeader('Content-Type', $contentType);
68
private function addContentLength(
69
RequestInterface $request,
72
// Set the Content-Length header if it can be determined, and never
73
// send a Transfer-Encoding: chunked and Content-Length header in
75
if ($request->hasHeader('Content-Length')) {
76
// Remove transfer-encoding if content-length is set.
77
$request->removeHeader('Transfer-Encoding');
81
if ($request->hasHeader('Transfer-Encoding')) {
85
if (null !== ($size = $body->getSize())) {
86
$request->setHeader('Content-Length', $size);
87
$request->removeHeader('Transfer-Encoding');
88
} elseif ('1.1' == $request->getProtocolVersion()) {
89
// Use chunked Transfer-Encoding if there is no determinable
90
// content-length header and we're using HTTP/1.1.
91
$request->setHeader('Transfer-Encoding', 'chunked');
92
$request->removeHeader('Content-Length');
96
private function addExpectHeader(
97
RequestInterface $request,
100
// Determine if the Expect header should be used
101
if ($request->hasHeader('Expect')) {
105
$expect = $request->getConfig()['expect'];
107
// Return if disabled or if you're not using HTTP/1.1
108
if ($expect === false || $request->getProtocolVersion() !== '1.1') {
112
// The expect header is unconditionally enabled
113
if ($expect === true) {
114
$request->setHeader('Expect', '100-Continue');
118
// By default, send the expect header when the payload is > 1mb
119
if ($expect === null) {
123
// Always add if the body cannot be rewound, the size cannot be
124
// determined, or the size is greater than the cutoff threshold
125
$size = $body->getSize();
126
if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
127
$request->setHeader('Expect', '100-Continue');