web-dev-qa-db-ja.com

CURLにhttp / 1.1を要求するように強制する方法は?または、別の問題が発生している可能性があります。

フレームワークで機能するコード(コードAと名付けましょう)があり、それを別のフレームワークで機能させたいと考えています。コードの作業片は、次のようなCURLを使用してPOSTリクエストを成功させます(CURLOPT_VERBOSEをオンにしたリクエスト)。

* Connected to Android.clients.google.com (216.58.209.238) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /Applications/MAMP/Library/OpenSSL/cert.pem
    CApath: none
* SSL connection using TLSv1.2 / ECDHE-ECDSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: C=US; ST=California; L=Mountain View; O=Google Inc; CN=*.google.com
*  start date: Jan 18 19:17:59 2017 GMT
*  expire date: Apr 12 18:51:00 2017 GMT
*  subjectAltName: Host "Android.clients.google.com" matched cert's "Android.clients.google.com"
*  issuer: C=US; O=Google Inc; CN=Google Internet Authority G2
*  SSL certificate verify ok.
> POST /auth HTTP/1.1
Host: Android.clients.google.com
Accept: */*
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 97

ここのhttpフレームワーク(具体的にはyii2/httpclient)には依存関係が多すぎて他のプロジェクトに導入できないため、次のように低レベルで再作成しようとしています(コードBと名付けましょう)。

<?php 
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'post-data-here');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, 'https://Android.clients.google.com/auth');
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/x-www-form-urlencoded; charset=UTF-8"]); // just because I'm desperate
curl_setopt($ch, CURLOPT_VERBOSE, true);
$content = curl_exec($ch);

私は同じ結果になると期待していますが、これは私が得るものです:

* Connected to Android.clients.google.com (216.58.209.238) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.google.com
* Server certificate: Google Internet Authority G2
* Server certificate: GeoTrust Global CA
> POST /auth HTTP/1.1
Host: Android.clients.google.com
Accept: */*
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 97
* upload completely sent off: 97 out of 97 bytes
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: Mon, 01 Jan 1990 00:00:00 GMT
< Date: Fri, 27 Jan 2017 12:07:12 GMT
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< Server: GSE
< Alt-Svc: clear
< Accept-Ranges: none
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
<HTML>
<HEAD>
<TITLE>HTTP Version Not Supported</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>HTTP Version Not Supported</H1>
<H2>Error 505</H2>
</BODY>
</HTML>

有効な応答の代わりに、「エラー505:サポートされていないHTTPバージョン」が表示されます。唯一の違いは、実際のコードは「ALPN、http/1.1を提供する」ことを試み、後者のコードはそれを行わないことです。そしてその後の証明書の部分ですが、コードAでこれが言及されたことは一度もないので、それを提供するために何が行われるのかわかりません。

両方のバージョンのコードは同じサーバー、同じバージョンのPHP(5.6)およびCURL(7.51.0)で実行されます。詳細ログの違いは、データが送信される前に開始されるので、正しく設定されていないデータやヘッダーについてではありません。

私がこれまでに試したこと(ほとんどまたはまったく効果なし):

  1. curl_setopt($ ch、CURLOPT_SSL_ENABLE_ALPNなど)-CURLOPT_SSL_ENABLE_ALPNがまったく定義されていないため機能しません(このバージョンのCURLに存在する必要がありますが、何が問題なのかわからないため)
  2. curl_setopt($ ch、CURLOPT_SSL_VERIFYPEERなど)
  3. curl_setopt($ ch、CURLOPT_SSL_VERIFYHOST、何でも)
  4. curl_setopt($ ch、CURLOPT_SSLVERSION、何でも)
  5. 私がここに表示することさえ恥ずかしい他のいくつかの絶望的な愚かなもの

作業コードをできるだけ深く学習しようとしましたが、単純なHTTP POSTでは何も実行しないようです。私はすべてのcurl_setoptを追跡しましたが、コードで使用したcurl_setoptだけがあり、余分なものはないようです。それでも動作しますが、私のコードは動作しません。

私はコマンドラインを使用して同じことを作ってみました:

$ curl https://Android.clients.google.com/auth -v --http1.1 -X POST --no-alpn --no-npn --data "copypasted-post-data-from-code-B-and-yes-its-urlencoded"

正しい結果を得ました:

*   Trying 216.58.209.238...
* TCP_NODELAY set
* Connected to Android.clients.google.com (216.58.209.238) port 443 (#0)
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /Applications/MAMP/Library/OpenSSL/cert.pem
  CApath: none
...
> POST /auth HTTP/1.1
> Host: Android.clients.google.com
> User-Agent: curl/7.51.0
> Accept: */*
> Content-Length: 97
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 97 out of 97 bytes
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: Mon, 01 Jan 1990 00:00:00 GMT
< Date: Fri, 27 Jan 2017 13:22:27 GMT
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< Server: GSE
< Alt-Svc: clear
< Accept-Ranges: none
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
<
SID=BAD_COOKIE
LSID=BAD_COOKIE
Auth=here-s-the-data-i-need
12
Andrey

わかりました。

実際、コードBのコードの前に、さらに別のライブラリ(正確にはHttpful)を使用して実行された別の要求があり、要求が何らかの形で混乱しているようです。クリーンなcurl_init()で実行されるリクエストに何か影響がある可能性があることを知りませんでした。

とにかく、問題のリクエストの前にすべてのHttpful呼び出しを低レベルの呼び出しに置き換えたところ、すべてが正常に機能しました。

0
Andrey

Error 505: HTTP Version Not Supportedは、curl/libcurlによって返されるエラー文字列ではなく、通信しているサーバーからcontentのように聞こえます。ヘッダーを含む完全なHTTP応答を表示するとしたら、おそらくそれがわかります。

したがって、カールは毎回問題なく機能したので、さまざまなカールオプションをいじってみてもまったく意味がありませんでした。また、curlコマンドラインツールを使用して、動作しようとしているホストに対して次のことを確認できます。

curl https://Android.clients.google.com/auth -v --http1.1 -X POST --no-alpn --no-npn

このコマンドラインは、TLSとHTTPの両方の「レイヤー」が適切であることを示しています。

別の質問 here が間違ったデータ(URLエンコードされていない)を渡したときに同様のエラーが発生しました。多分あなたは似たようなものを持っていて、新しいフレームワークへの切り替えのためにそれを逃したのですか?

5
Daniel Stenberg