Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force CURL to ask for http/1.1? Or maybe there's another issue, not sure

Tags:

php

curl

ssl

I've got a piece of code (let's name it Code A) working in a framework and I want to make it work in another framework. The working piece of code makes a successful POST request using CURL like this (request with CURLOPT_VERBOSE on):

* 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 

The http framework here (yii2/httpclient, to be specific) has too many dependencies to bring it to the other project so I'm trying to recreate it on low level like this (let's name it Code 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); 

I'm expecting that to have the same result, but this is what I get:

* 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> 

And instead of a valid response I get "Error 505: HTTP Version Not Supported". The only difference I see is that the working code tries to "ALPN, offering http/1.1" while the latter code doesn't do that. And the certificate part after that, but it's never ever mentioned in code A so I'm not sure what does it do to provide it.

Both versions of code run on the same server, same version of PHP (5.6) and CURL (7.51.0). The difference in verbose log starts BEFORE any data being sent, so I guess it's not about any data or headers being set incorrectly.

What I tried so far (with little or no effect):

  1. curl_setopt($ch, CURLOPT_SSL_ENABLE_ALPN, whatever) - does not work because CURLOPT_SSL_ENABLE_ALPN is not defined at all (although it must be in this version of CURL, not sure what's wrong)
  2. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, whatever)
  3. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, whatever)
  4. curl_setopt($ch, CURLOPT_SSLVERSION, whatever)
  5. some other desperate silly stuff I'm even ashamed to show here

I've tried to learn the working code as deep as I could but it seems that it doesn't do anything over the simple HTTP POST. I tracked every curl_setopt it makes and it seems there are only these curl_setopt I used in my code, nothing extra. Still, it works and my code doesn't.

I've tried making the same using the command line:

$ 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" 

Got the correct result:

*   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 
like image 444
Andrey Avatar asked Jan 27 '17 12:01

Andrey


People also ask

How do I use the curl command to request?

To make a GET request using Curl, run the curl command followed by the target URL. Curl automatically selects the HTTP GET request method unless you use the -X, --request, or -d command-line option.

Which HTTP version does curl use?

curl defaults to HTTP/1.1 for HTTP servers but if you connect to HTTPS and you have a curl that has HTTP/2 abilities built-in, it attempts to negotiate HTTP/2 automatically or falls back to 1.1 in case the negotiation failed. Non-HTTP/2 capable curls get 1.1 over HTTPS by default.

How do I get my browser to request a curl?

From Chrome and Edge On the line of the specific resource you are interested in, you right-click with the mouse and you select "Copy as cURL" and it will generate a command line for you in your clipboard. Paste that in a shell to get a curl command line that makes the transfer.

How do you curl a URL?

The syntax for the curl command is as follows: curl [options] [URL...] In its simplest form, when invoked without any option, curl displays the specified resource to the standard output. The command will print the source code of the example.com homepage in your terminal window.


1 Answers

Error 505: HTTP Version Not Supported is not an error string that is returned by curl/libcurl, that sounds like content that you receive from the server you're communicating with. If you would show us the full HTTP response including headers, we could probably have seen that.

So, all your playing around with different curl options was to no gain because curl worked fine every single time. You could also verify that with using the curl command line tool against the host you're trying to get to work:

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

This command line shows that both the TLS and HTTP "layers" are fine.

Another question here got a similar error when they passed in the wrong data (not url encoded). Maybe you have something similar and because of your switch to a new framework you missed it?

like image 104
Daniel Stenberg Avatar answered Oct 05 '22 19:10

Daniel Stenberg