BidirectionalStream backup impl |
|
Issue descriptionSometimes Cronet fails to load. There are various reasons why this happens (out of date shared libraries, broken app installations, misconfigured devices with the wrong shared libraries) and we've tried to solve or mitigate most of them, but Cronet still fails to load sometimes. Many Cronet embedders realize this and have a backup plan for what to do when Cronet doesn't load. Some embedders fall back to using Cronet's java-only fallback UrlRequest impl that's based on the Android system HttpURLConnection API. Currently there is no BidirectionalStream backup implementation, which forces some embedders to turn off all GRPC-based features when Cronet fails to load. We've talked for years about having a backup java-only BidirectionalStream impl. I wanted to file a bug to track ideas and progress related to this initiative. Before progressing towards an implementation I think we should do a little due diligence and see if there is demand for such a fallback impl. I did a little bit of thinking about whether a BidirectionalStream fallback impl is even possible: Being a fallback impl, performance and robustness and complete compatibility are low priorities, while general compatibility and small size are high priorities. I think use of QUIC is off the table, to keep it simple. I think it would have to be based on HTTP/2 over TLS over TCP. To be useful to embedders it would need to be secure and encrypted. HTTP/2 can be negotiated one of a few ways: 1. Via an Upgrade header from HTTP/1.1. I don't think this is viable because I believe many servers only support this via cleartext which isn't useful to embedders. 2. Via NPN. I don't think this is viable as NPN deprecation was announced in 2013 and server support may disappear at any time. 3. Via ALPN. ALPN support was added in Android KitKat (see public b/36973797) though it looks like the API is still hidden today (android.net.SSLCertificateSocketFactory.setAlpnProtocols()). This means that without major heroics unsuitable for a space-constrained backup implementation, ALPN and hence HTTP/2 and this back up impl may only be viable for 96% of Android devices (the public Android dashboard (https://developer.android.com/about/dashboards/) indicates 96% of devices are KitKat+).
,
Aug 8
Worked a bit more on my prototype: https://chromium-review.googlesource.com/c/chromium/src/+/1167905 HPACK decoding seems to work. It can now successfully communicate with www.google.com. |
|
►
Sign in to add a comment |
|
Comment 1 by pauljensen@chromium.org
, Aug 3I did a little experimenting and was able to communicate with Google via HTTP/2 negotiated via ALPN: try { SSLCertificateSocketFactory f = new SSLCertificateSocketFactory(10000); byte[][] protocols = new byte[][]{"h2".getBytes()}; Method setAlpnProtocols = f.getClass().getDeclaredMethod("setAlpnProtocols", byte[][].class); setAlpnProtocols.invoke(f, new Object[]{protocols}); Socket s = f.createSocket("www.google.com", 443); Log.e("PJPJ", "socket connected!"); OutputStream o = s.getOutputStream(); InputStream is = s.getInputStream(); // send connection preface, see HTTP/2 section 3.5 o.write(new byte[]{ 0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a }); // send empty settings frame as required by spec o.write(new byte[]{ 0x00, 0x00, 0x00, // 0 sized payload 0x04, // settings frame 0x00, // no flags 0x00, 0x00, 0x00, 0x00 // 0 stream identifier }); // header frame o.write(new byte[]{ 0x00, 0x00, 0x03, // 3 sized payload 0x01, // headers frame 0x05, // EOS, EOH flags 0x00, 0x00, 0x00, 0x01, // 1 stream identifier (byte)0x82, // :method: GET (byte)0x84, // :path: / (byte)0x87 // :scheme: https }); while(true) { String st = ""; byte[] bs = new byte[3]; is.read(bs); for (int i = 0; i < 3; i++) { st = st + " " + bs[i]; } byte[] b = new byte[bs[2] + 9 - 3]; is.read(b); for (int i = 0; i < b.length; i++) { st = st + " " + b[i]; } Log.e("PJPJ", "Read: " + st); } } catch (Exception e) { Log.e("PJPJ", "bad", e); } From logging I could see Google sending me back multiple HTTP/2 frames: 08-03 14:34:15.977 3933 3986 E PJPJ : socket connected! 08-03 14:34:16.026 3933 3986 E PJPJ : Read: 0 0 18 4 0 0 0 0 0 0 3 0 0 0 100 0 4 0 16 0 0 0 6 0 0 64 0 08-03 14:34:16.026 3933 3986 E PJPJ : Read: 0 0 4 8 0 0 0 0 0 0 15 0 1 08-03 14:34:16.026 3933 3986 E PJPJ : Read: 0 0 0 4 1 0 0 0 0 08-03 14:34:16.028 3933 3986 E PJPJ : Read: 0 0 76 1 4 0 0 0 1 -116 95 -110 73 124 -91 -119 -45 77 31 106 18 113 -40 -126 -90 14 27 -16 -84 -9 64 -117 -80 -78 -106 -53 11 98 -43 -98 -125 19 -41 -120 -88 -21 88 89 75 101 -123 -77 92 -125 11 109 -73 0 -125 -112 105 47 -106 -61 97 -66 -108 3 42 67 108 -54 8 1 121 64 -67 113 -106 -82 5 -59 49 104 -33 08-03 14:34:16.028 3933 3986 E PJPJ : Read: 0 0 4 3 0 0 0 0 1 0 0 0 1 08-03 14:38:15.188 3933 3986 E PJPJ : Read: 0 0 25 7 0 0 0 0 0 0 0 0 1 0 0 0 0 115 101 115 115 105 111 110 95 116 105 109 101 100 95 111 117 116 08-03 14:38:15.190 3933 3986 E PJPJ : Read: 0 0 0 0 0 0 0 0 0 08-03 14:38:23.866 3933 3986 E PJPJ : Read: 0 0 0 0 0 0 0 0 0 08-03 14:38:23.866 3933 3986 E PJPJ : Read: 0 0 0 0 0 0 0 0 0