73 $parts = explode(
':', $server, 2 );
74 $this->host = $parts[0];
75 $this->port = $parts[1] ?? 80;
85 if ( $this->socket !==
null ) {
91 $this->
log(
"DNS error" );
95 $this->socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
96 socket_set_nonblock( $this->socket );
97 Wikimedia\suppressWarnings();
98 $ok = socket_connect( $this->socket,
$ip, $this->port );
99 Wikimedia\restoreWarnings();
101 $error = socket_last_error( $this->socket );
102 if ( $error !== self::EINPROGRESS ) {
103 $this->
log(
"connection error: " . socket_strerror( $error ) );
117 if ( $this->readState ==
'idle' ) {
132 if ( !strlen( $this->writeBuffer ) ) {
149 if ( $this->ip ===
null ) {
153 throw new MWException(
'$wgCdnServers does not support IPv6' );
155 Wikimedia\suppressWarnings();
156 $this->ip = gethostbyname( $this->host );
157 if ( $this->ip === $this->host ) {
160 Wikimedia\restoreWarnings();
172 $this->socket =
false;
179 if ( $this->socket ) {
180 Wikimedia\suppressWarnings();
181 socket_set_block( $this->socket );
182 socket_shutdown( $this->socket );
183 socket_close( $this->socket );
184 Wikimedia\restoreWarnings();
186 $this->socket =
null;
187 $this->readBuffer =
'';
198 $url = str_replace(
"\n",
'', $url );
202 $host = $url[
'host'];
203 if ( isset( $url[
'port'] ) && strlen( $url[
'port'] ) > 0 ) {
204 $host .=
":" . $url[
'port'];
206 $path = $url[
'path'];
207 if ( isset( $url[
'query'] ) && is_string( $url[
'query'] ) ) {
210 $request[] =
"PURGE $path HTTP/1.1";
211 $request[] =
"Host: $host";
213 wfDeprecated(
'$wgSquidPurgeUseHostHeader = false',
'1.33' );
214 $request[] =
"PURGE $url HTTP/1.0";
216 $request[] =
"Connection: Keep-Alive";
217 $request[] =
"Proxy-Connection: Keep-Alive";
223 $this->requests[] = implode(
"\r\n", $request );
224 if ( $this->currentRequestIndex ===
null ) {
233 return strlen( $this->writeBuffer ) == 0 && $this->readState ==
'idle';
240 if ( !strlen( $this->writeBuffer ) ) {
248 if ( strlen( $this->writeBuffer ) <= self::BUFFER_SIZE ) {
252 $buf = substr( $this->writeBuffer, 0, self::BUFFER_SIZE );
255 Wikimedia\suppressWarnings();
256 $bytesSent = socket_send(
$socket, $buf, strlen( $buf ), $flags );
257 Wikimedia\restoreWarnings();
259 if ( $bytesSent ===
false ) {
260 $error = socket_last_error(
$socket );
261 if ( $error != self::EAGAIN && $error != self::EINTR ) {
262 $this->
log(
'write error: ' . socket_strerror( $error ) );
268 $this->writeBuffer = substr( $this->writeBuffer, $bytesSent );
281 Wikimedia\suppressWarnings();
282 $bytesRead = socket_recv(
$socket, $buf, self::BUFFER_SIZE, 0 );
283 Wikimedia\restoreWarnings();
284 if ( $bytesRead ===
false ) {
285 $error = socket_last_error(
$socket );
286 if ( $error != self::EAGAIN && $error != self::EINTR ) {
287 $this->
log(
'read error: ' . socket_strerror( $error ) );
291 } elseif ( $bytesRead === 0 ) {
297 $this->readBuffer .= $buf;
306 switch ( $this->readState ) {
311 $lines = explode(
"\r\n", $this->readBuffer, 2 );
312 if ( count(
$lines ) < 2 ) {
315 if ( $this->readState ==
'status' ) {
320 $this->readBuffer =
$lines[1];
323 if ( $this->bodyRemaining !==
null ) {
324 if ( $this->bodyRemaining > strlen( $this->readBuffer ) ) {
325 $this->bodyRemaining -= strlen( $this->readBuffer );
326 $this->readBuffer =
'';
329 $this->readBuffer = substr( $this->readBuffer, $this->bodyRemaining );
330 $this->bodyRemaining = 0;
336 $this->readBuffer =
'';
340 throw new MWException( __METHOD__ .
': unexpected state' );
348 if ( !preg_match(
'!^HTTP/(\d+)\.(\d+) (\d{3}) (.*)$!',
$line, $m ) ) {
349 $this->
log(
'invalid status line' );
353 list( , , ,
$status, $reason ) = $m;
356 $this->
log(
"unexpected status code: $status $reason" );
360 $this->readState =
'header';
367 if ( preg_match(
'/^Content-Length: (\d+)$/i',
$line, $m ) ) {
368 $this->bodyRemaining = intval( $m[1] );
369 } elseif (
$line ===
'' ) {
370 $this->readState =
'body';
375 if ( $this->currentRequestIndex !==
null ) {
376 unset( $this->requests[$this->currentRequestIndex] );
378 if ( count( $this->requests ) ) {
379 $this->readState =
'status';
380 $this->currentRequestIndex = key( $this->requests );
383 $this->readState =
'idle';
384 $this->currentRequestIndex =
null;
385 $this->writeBuffer =
'';
387 $this->bodyRemaining =
null;
393 protected function log( $msg ) {
394 wfDebugLog(
'squid', __CLASS__ .
" ($this->host): $msg" );