Issue
I publish a pod with the following spec:
Pod::Spec.new do |s|
s.name = "AirTurnInterface"
s.version = "4.7.0-b.6"
s.summary = "snip"
s.description = "snip"
s.license = { :file => 'LICENSE', :type => 'AirTurn' }
s.homepage = "snip"
s.author = { "Nick Brook" => "[email protected]" }
s.ios.deployment_target = "11.0"
s.frameworks = 'CoreBluetooth', 'GameController', 'Security', 'UIKit'
s.source = { :http => "https://airturn.com/framework/test/AirTurnInterface.#{s.version}.zip" }
s.vendored_frameworks = "Framework-dynamic/AirTurnInterface.xcframework"
end
This can be tested by putting the following in a file named test.podspec
and running pod spec lint test.podspec
.
Until recently, this worked fine. Now, running pod spec lint
fails when downloading the zip with the error:
curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
It also provides the curl command used:
/opt/homebrew/opt/curl/bin/curl -f -L -o /var/folders/9j/jqc5qhp922b7c8jhrvkh7h8m0000gn/T/d20221021-48752-1fqts5p/file.zip https://airturn.com/framework/test/AirTurnInterface.4.7.0-b.6.zip --create-dirs --netrc-optional --retry 2 -A 'CocoaPods/1.11.3 cocoapods-downloader/1.5.1'
The strange thing is, this command works when run directly, it only fails when run from Cocoapods (ruby). I've also tried just performing the command from a simple ruby script, which works fine. Something about Cocoapods is causing the command to fail. I've modified Cocoapods (gems/cocoapods-downloader-1.5.1/lib/cocoapods-downloader/http.rb
) to pass -v
to curl, which provides the following output:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 35.209.185.188:443...
* Connected to airturn.com (35.209.185.188) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [88 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [187 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [19 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [4039 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [264 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
* subject: CN=*.airturn.com
* start date: Oct 5 00:07:55 2022 GMT
* expire date: Jan 3 00:07:54 2023 GMT
* subjectAltName: host "airturn.com" matched cert's "airturn.com"
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
} [5 bytes data]
* h2h3 [:method: GET]
* h2h3 [:path: /framework/test/AirTurnInterface.4.7.0-b.6.zip]
* h2h3 [:scheme: https]
* h2h3 [:authority: airturn.com]
* h2h3 [user-agent: 'CocoaPods/1.11.3 cocoapods-downloader/1.5.1']
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x15580f600)
} [5 bytes data]
> GET /framework/test/AirTurnInterface.4.7.0-b.6.zip HTTP/2
> Host: airturn.com
> user-agent: 'CocoaPods/1.11.3 cocoapods-downloader/1.5.1'
> accept: */*
>
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [265 bytes data]
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
{ [265 bytes data]
* old SSL session ID is stale, removing
{ [5 bytes data]
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
} [5 bytes data]
* HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
* Connection #0 to host airturn.com left intact
curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
Forcing http1.1 with --http1.1 doesn't help:
curl: (52) Empty reply from server
I don't know what to try next to debug further!
Solution
I think your CocoaPods problem is that your server bails on the User-Agent
that the CocoaPods script is sending. If you place the curl -v
output from CocoaPods right next to the curl -v
output from the command line, note the following difference:
user-agent: CocoaPods/1.10.1 cocoapods-downloader/1.4.0
vs
user-agent: 'CocoaPods/1.10.1 cocoapods-downloader/1.4.0'
The first one is from the command line, which works, and the second one is from CocoaPods, which causes your server to terminate the connection. If I’m reading the relevant RFCs correctly, the CocoaPods version technically satisfies the grammar defined for the User-Agent
field, so that’s probably why this hasn’t ever been noticed before. Your server, however, seems to inspect the User-Agent
more closely than others and rejects the one that CocoaPods sends.
So, my guess is that you can resolve this by making your server accept any User-Agent
.
Answered By - min-jt Answer Checked By - Clifford M. (WPSolving Volunteer)