iOS端末へのPush通知の送信にどうしても成功できず困っています。
どうもCURLからhttp2での通信が行えていないところまではなんとかわかってきたのですが・・
原因がどうしても特定できないのでなにかご存知のかたいらっしゃいましたらアドバイスいただければ幸いです。
前提・実現したいこと
サーバーサイドからAPNsのAPIを直接叩いてiOS端末にPush通知を送るためのテストをしたいと考えています。
下記のURLを参考にしてスクリプトを作成して送信テストを行いました。
https://qiita.com/yimajo/items/58565070d39acb4d5e71
発生している問題・エラーメッセージ
後述するPushのテスト送信用のスクリプトを実際に実行してみると下記のようなレスポンスが返ってきます。
* Trying 17.188.164.14... * TCP_NODELAY set * Connected to api.push.apple.com (17.188.164.14) port 443 (#0) * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Request CERT (13): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Certificate (11): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS handshake, CERT verify (15): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 * Server certificate: * subject: CN=api.push.apple.com; OU=management:idms.group.533599; O=Apple Inc.; ST=California; C=US * start date: Jan 6 00:14:15 2018 GMT * expire date: Feb 5 00:14:15 2020 GMT * subjectAltName: host "api.push.apple.com" matched cert's "api.push.apple.com" * issuer: CN=Apple IST CA 2 - G1; OU=Certification Authority; O=Apple Inc.; C=US * SSL certificate verify ok. > POST /3/device/****************************** HTTP/1.1 > Host: api.push.apple.com > User-Agent: curl/7.61.1 > Accept: */* > apns-priority: 10 > apns-expiration: 0 > apns-topic: ****** > Content-Length: 35 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 35 out of 35 bytes * Closing connection 0 * TLSv1.2 (OUT), TLS alert, close notify (256): Unexpected HTTP/1.x request: POST /3/device/*****
curlのオプションでhttp2を指定しているにもかかわらずHTTP/1.1で送信されていることがわかります。
該当のソースコード
テスト送信用のスクリプトとして下記をサーバー上で実行しています
sh
1#!/bin/sh 2 3pemfile=$1 4token=$2 5pushData='{"aps": {"alert": "push dev test"}}' 6 7bundleIdentifier="******" 8 9#appleUri="https://api.development.push.apple.com/3/device/" 10appleUri="https://api.push.apple.com/3/device/" 11 12curl -v \ 13-d "$pushData" \ 14-H "apns-priority: 10" \ 15-H "apns-expiration: 0" \ 16-H "apns-topic: ${bundleIdentifier}" \ 17--cert ${pemfile} \ 18--http2 \ 19--output \ 20- \ 21${appleUri}${token}
試したこと
現象の原因がどうしてもわからず、相手サーバー側にある可能性を確認するために、送信先のURLをAPNsではなく、仮にHTTP2のテストサーバーであるという https://nghttp2.org/ に変更して試してみました。
(参考: https://github.com/nghttp2/nghttp2)
すると、こちらのサーバーではhttp2で通信できているように思います。(当然404にはなりますが)
* Trying 139.162.123.134... * TCP_NODELAY set * Connected to nghttp2.org (139.162.123.134) port 443 (#0) * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * NPN, negotiated HTTP2 (h2) * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Next protocol (67): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-ECDSA-AES256-GCM-SHA384 * Server certificate: * subject: CN=nghttp2.org * start date: Aug 20 00:00:10 2018 GMT * expire date: Nov 18 00:00:10 2018 GMT * subjectAltName: host "nghttp2.org" matched cert's "nghttp2.org" * issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3 * SSL certificate verify ok. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x1aab5f0) > POST /2c0d299877036d25c1015f5318aaeaee0fad1381d043216b61d4bf656016fc12 HTTP/2 > Host: nghttp2.org > User-Agent: curl/7.61.1 > Accept: */* > apns-priority: 10 > apns-expiration: 0 > apns-topic: ******** > Content-Length: 35 > Content-Type: application/x-www-form-urlencoded > * Connection state changed (MAX_CONCURRENT_STREAMS == 100)! * We are completely uploaded and fine < HTTP/2 404 < date: Sun, 28 Oct 2018 14:08:41 GMT < content-type: text/plain; charset=utf-8 < content-length: 9 < x-backend-header-rtt: 0.001965 < strict-transport-security: max-age=31536000 < server: nghttpx < via: 2 nghttpx < x-frame-options: SAMEORIGIN < x-xss-protection: 1; mode=block < x-content-type-options: nosniff < * Connection #0 to host nghttp2.org left intact
APNsはHTTP/2をベースに通信するとドキュメントにも記載がありますので、
APNsのAPI側が対応していないとは考えづらく、
原因に見当がつかない状態です。
補足情報(FW/ツールのバージョンなど)
使用している各種ツールのバージョンを記載いたします。
不足などございましたらご指摘いただけえますでしょうか。
curl
1root@e6c018ac81eb:/var/www/html# curl --version 2curl 7.61.1 (x86_64-pc-linux-gnu) libcurl/7.61.1 OpenSSL/1.0.1t zlib/1.2.8 nghttp2/1.35.0-DEV 3Release-Date: 2018-09-05 4Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 5Features: AsynchDNS IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy
openssl
1root@e6c018ac81eb:/var/www/html# openssl version 2OpenSSL 1.0.2g 1 Mar 2016
debian
1root@e6c018ac81eb:/var/www/html# cat /etc/debian_version 28.10
追記 2018/10/29
すこしづつわかってきました。
どうもAPNsがHTTP2でもAPLNのみを受け付けており、NPNは受け付けていない様子・・。
そのせいでAPLNに対応していない環境からの通信がHTTP1.1になってしまっている。
とはいえ、OpenSSL1.0.2を入れたので、APLNに対応したCURLが入っているはずなのですが・・
さらに調査中です・・
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。