Что делать с дополнительным HTTP-заголовком из прокси-сервера?

В нашей среде требуется использование исходящего прокси для внешних служб. Обычно это не проблема. В этом случае с Twilio, добавленный дополнительный заголовок прерывает клиента.

Исходящие заголовки:

POST /2010-04-01/Accounts/FOO/SMS/Messages.json HTTP/1.1
Authorization: Basic FOO==
User-Agent: twilio-php/3.10.0
Host: api.twilio.com
Accept: */*
Accept-Charset: utf-8
Content-Type: application/x-www-form-urlencoded
Content-Length: 108

Заголовки ответов:

HTTP/1.0 200 Connection established

HTTP/1.1 201 Created
Server: nginx
Date: Thu, 06 Jun 2013 14:39:24 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 551
Connection: close
X-Powered-By: PHP/5.3.11

Я могу предположить, что прокси-сервер добавляет дополнительный HTTP-заголовок.

Клиент Twilio проверяет:

list($head, $body) = ($parts[0] == 'HTTP/1.1 100 Continue') 

Как я понимаю, существуют времена или версии curl, которые автоматически добавят заголовок Expect в запрос, и HTTP 100 будет возвращен в ответе, но в этом случае это не так, и ответ будет равен 200 Соединение установлено. Для чего стоит добавить пустой Expect: или Expect: бекон не изменил результаты.

Я бы предпочел не слишком сильно взламывать клиента Twilio, и мне особенно хотелось бы избежать добавления || $parts [0] == 'HTTP/1.0 200 Connection установлено', как это кажется грязным.

Можно ли отправить заголовок запроса в том, что будет подавлять/скрывать дополнительный заголовок? Или, вариант завитка, который я не вижу, чтобы его игнорировать?

Исходящий прокси-сервер Linux/Squid

Ответ 1

Проблема с прокси-сервером - это то, с чем сталкивается множество сценариев. Предпочтительным решением, которое я могу найти в Интернете, является просто добавление следующих строк кода.

<?php
// cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string
if (false !== stripos($response, "HTTP/1.0 200 Connection established\r\n\r\n")) {
  $response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $response);
}
?>

Теперь, чтобы добавить это к клиенту twilio, было бы действительно грязно. К счастью, вы можете использовать пространства имен для воссоздания собственных функций. См. Следующий пример.

<?php
namespace FakeCurl;

//create curl_exec function with same name, but its created in the FakeCurl namespace now.
function curl_exec($ch) {
  //execute the actual curl_exec function in the main namespace
  $response =  \curl_exec($ch);

  // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string
  if (false !== stripos($response, "HTTP/1.0 200 Connection established\r\n\r\n")) {
    $response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $response);
  } 

  return "ADDED TO RESPONSE\r\n\r\n".$response;
}

//make a regular curl request, no alterations.

$curl = curl_init();
curl_setopt_array( $curl, array(
    CURLOPT_HEADER => true,
    CURLOPT_NOBODY => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_URL => 'http://stackoverflow.com' ) );
$response = curl_exec( $curl );
curl_close( $curl );

echo '<pre>'.$response.'</pre>';

?>

Выход

ADDED TO RESPONSE

HTTP/1.1 200 OK
Cache-Control: public, max-age=11
Content-Length: 191951
Content-Type: text/html; charset=utf-8
Expires: Wed, 12 Jun 2013 07:09:02 GMT
Last-Modified: Wed, 12 Jun 2013 07:08:02 GMT
Vary: *
X-Frame-Options: SAMEORIGIN
Date: Wed, 12 Jun 2013 07:08:49 GMT

Поэтому для использования с клиентом twilio вам нужно поставить на верхнюю часть вашего script следующее:

<?php
namespace FakeCurl;
function curl_exec($ch) {
  $response =  \curl_exec($ch);

  // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string
  if (false !== stripos($response, "HTTP/1.0 200 Connection established\r\n\r\n")) {
    $response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $response);
  } 

  return $response;
}

include("twilio.php");
?>

Если по какой-либо причине произойдет сбой по имени, я бы добавил простую функцию вне клиента twilio.

<?php
function fixProxyResponse($response) {
  // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string
  if (false !== stripos($response, "HTTP/1.0 200 Connection established\r\n\r\n")) {
    $response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $response);
  } 

  return $response;
}

И затем измените twilio script TinyHttp.php и измените только следующую строку (~ linenr 63)

if ($response = curl_exec($curl)) {
  $parts = explode("\r\n\r\n", $response, 3);
  list($head, $body) = ($parts[0] == 'HTTP/1.1 100 Continue')

to

if ($response = curl_exec($curl)) {
  $parts = explode("\r\n\r\n", fixProxyResponse($response), 3);
  list($head, $body) = ($parts[0] == 'HTTP/1.1 100 Continue')

Ответ 2

Некоторые очень поздние разъяснения. Когда вы подключаетесь к серверу SSL/TLS через прокси-сервер, прокси устанавливает туннель, используя HTTP CONNECT. Это описано в RFC2817 и просроченной спецификации туннелирования, а не RFC2616.

Первоначальная спецификация туннелирования требовала, чтобы прокси-сервер возвращал "200 Connection Established" клиенту, когда он успешно подключился к серверу, и это то, что вы видите. Это потенциально сопровождается большим количеством заголовков, а затем пустой строкой, прежде чем соединение станет прозрачным и вы получите фактический ответ от сервера. Итак, вы получаете два набора заголовков. RFC 2817 расслабляет это и позволяет любой 2xx ответ на запрос CONNECT.

Это означает, что вы не можете полагаться на обнаружение и удаление одной строки заголовка с использованием php-кода выше. Может быть более одной строки, и первая строка может не иметь 200 кода и не может содержать строку, установленную "соединение". Вы должны быть готовы обнаружить два полных набора заголовков.

cURL удалил исходный ответ на соединение до 7.11.1 в 2004 году, но теперь отправляет все обратно клиенту. Подробнее см. здесь.