From 6c71fab75615367a46b87211e4463c040272d9d4 Mon Sep 17 00:00:00 2001 From: Ghislain Loaec Date: Wed, 4 Feb 2015 11:43:18 +0100 Subject: [PATCH] First Draft --- .cordova/config.json | 10 + .gitignore | 5 + config.xml | 70 + hooks/README.md | 196 ++ platforms/android/.gitignore | 14 + platforms/android/.project | 71 + platforms/android/AndroidManifest.xml | 14 + platforms/android/CordovaLib/.project | 1 + .../android/CordovaLib/AndroidManifest.xml | 23 + .../ant-build/AndroidManifest.cordova.xml | 23 + .../ant-build/AndroidManifest.xml.d | 2 + .../android/CordovaLib/ant-build/build.prop | 10 + .../android/CordovaLib/ant-build/classes.jar | Bin 0 -> 342622 bytes .../classes/com/squareup/okhttp/Address.class | Bin 0 -> 3356 bytes .../com/squareup/okhttp/Connection.class | Bin 0 -> 9543 bytes .../squareup/okhttp/ConnectionPool$1.class | Bin 0 -> 2542 bytes .../squareup/okhttp/ConnectionPool$2.class | Bin 0 -> 650 bytes .../com/squareup/okhttp/ConnectionPool.class | Bin 0 -> 6977 bytes .../okhttp/Dispatcher$RealResponseBody.class | Bin 0 -> 1457 bytes .../com/squareup/okhttp/Dispatcher.class | Bin 0 -> 2919 bytes .../com/squareup/okhttp/Failure$1.class | Bin 0 -> 212 bytes .../com/squareup/okhttp/Failure$Builder.class | Bin 0 -> 1303 bytes .../classes/com/squareup/okhttp/Failure.class | Bin 0 -> 1231 bytes .../squareup/okhttp/HttpResponseCache$1.class | Bin 0 -> 2433 bytes .../squareup/okhttp/HttpResponseCache$2.class | Bin 0 -> 1046 bytes .../squareup/okhttp/HttpResponseCache$3.class | Bin 0 -> 833 bytes ...HttpResponseCache$CacheRequestImpl$1.class | Bin 0 -> 2012 bytes .../HttpResponseCache$CacheRequestImpl.class | Bin 0 -> 2150 bytes .../okhttp/HttpResponseCache$Entry.class | Bin 0 -> 8443 bytes ...HttpResponseCache$EntryCacheResponse.class | Bin 0 -> 1808 bytes ...sponseCache$EntrySecureCacheResponse.class | Bin 0 -> 3237 bytes .../squareup/okhttp/HttpResponseCache.class | Bin 0 -> 9921 bytes .../classes/com/squareup/okhttp/Job.class | Bin 0 -> 8622 bytes .../com/squareup/okhttp/MediaType.class | Bin 0 -> 3176 bytes .../okhttp/OkAuthenticator$Challenge.class | Bin 0 -> 1279 bytes .../okhttp/OkAuthenticator$Credential.class | Bin 0 -> 1748 bytes .../com/squareup/okhttp/OkAuthenticator.class | Bin 0 -> 682 bytes .../com/squareup/okhttp/OkHttpClient$1.class | Bin 0 -> 1394 bytes .../com/squareup/okhttp/OkHttpClient.class | Bin 0 -> 9240 bytes .../com/squareup/okhttp/OkResponseCache.class | Bin 0 -> 773 bytes .../com/squareup/okhttp/Request$1.class | Bin 0 -> 212 bytes .../com/squareup/okhttp/Request$Body$1.class | Bin 0 -> 1112 bytes .../com/squareup/okhttp/Request$Body$2.class | Bin 0 -> 1669 bytes .../com/squareup/okhttp/Request$Body.class | Bin 0 -> 2314 bytes .../com/squareup/okhttp/Request$Builder.class | Bin 0 -> 4187 bytes .../classes/com/squareup/okhttp/Request.class | Bin 0 -> 3633 bytes .../com/squareup/okhttp/Response$1.class | Bin 0 -> 215 bytes .../com/squareup/okhttp/Response$Body.class | Bin 0 -> 2397 bytes .../squareup/okhttp/Response$Builder.class | Bin 0 -> 3083 bytes .../squareup/okhttp/Response$Receiver.class | Bin 0 -> 362 bytes .../com/squareup/okhttp/Response.class | Bin 0 -> 3357 bytes .../com/squareup/okhttp/ResponseSource.class | Bin 0 -> 1201 bytes .../classes/com/squareup/okhttp/Route.class | Bin 0 -> 1915 bytes .../com/squareup/okhttp/RouteDatabase.class | Bin 0 -> 1331 bytes .../com/squareup/okhttp/TunnelRequest.class | Bin 0 -> 1654 bytes .../internal/AbstractOutputStream.class | Bin 0 -> 793 bytes .../com/squareup/okhttp/internal/Base64.class | Bin 0 -> 2649 bytes .../okhttp/internal/DiskLruCache$1.class | Bin 0 -> 1322 bytes .../okhttp/internal/DiskLruCache$2.class | Bin 0 -> 574 bytes ...Cache$Editor$FaultHidingOutputStream.class | Bin 0 -> 1942 bytes .../okhttp/internal/DiskLruCache$Editor.class | Bin 0 -> 4964 bytes .../okhttp/internal/DiskLruCache$Entry.class | Bin 0 -> 4472 bytes .../internal/DiskLruCache$Snapshot.class | Bin 0 -> 2381 bytes .../okhttp/internal/DiskLruCache.class | Bin 0 -> 16738 bytes .../com/squareup/okhttp/internal/Dns$1.class | Bin 0 -> 652 bytes .../com/squareup/okhttp/internal/Dns.class | Bin 0 -> 492 bytes .../FaultRecoveringOutputStream.class | Bin 0 -> 2434 bytes .../okhttp/internal/NamedRunnable.class | Bin 0 -> 954 bytes .../squareup/okhttp/internal/Platform$1.class | Bin 0 -> 233 bytes .../okhttp/internal/Platform$Android23.class | Bin 0 -> 2840 bytes .../okhttp/internal/Platform$Android41.class | Bin 0 -> 2635 bytes .../Platform$JdkWithJettyNpnPlatform.class | Bin 0 -> 3757 bytes .../internal/Platform$JettyNpnProvider.class | Bin 0 -> 2439 bytes .../squareup/okhttp/internal/Platform.class | Bin 0 -> 6516 bytes .../okhttp/internal/StrictLineReader$1.class | Bin 0 -> 1242 bytes .../okhttp/internal/StrictLineReader.class | Bin 0 -> 3300 bytes .../com/squareup/okhttp/internal/Util$1.class | Bin 0 -> 935 bytes .../com/squareup/okhttp/internal/Util.class | Bin 0 -> 9234 bytes .../http/AbstractHttpInputStream.class | Bin 0 -> 1873 bytes .../HeaderParser$CacheControlHandler.class | Bin 0 -> 323 bytes .../okhttp/internal/http/HeaderParser.class | Bin 0 -> 2182 bytes .../internal/http/HttpAuthenticator$1.class | Bin 0 -> 3578 bytes .../internal/http/HttpAuthenticator.class | Bin 0 -> 3718 bytes .../okhttp/internal/http/HttpDate$1.class | Bin 0 -> 1128 bytes .../okhttp/internal/http/HttpDate.class | Bin 0 -> 2204 bytes .../okhttp/internal/http/HttpEngine$1.class | Bin 0 -> 1349 bytes .../okhttp/internal/http/HttpEngine.class | Bin 0 -> 16486 bytes .../internal/http/HttpTransport$1.class | Bin 0 -> 258 bytes .../HttpTransport$ChunkedInputStream.class | Bin 0 -> 3989 bytes .../HttpTransport$ChunkedOutputStream.class | Bin 0 -> 3069 bytes ...HttpTransport$FixedLengthInputStream.class | Bin 0 -> 2111 bytes ...ttpTransport$FixedLengthOutputStream.class | Bin 0 -> 2068 bytes .../okhttp/internal/http/HttpTransport.class | Bin 0 -> 6941 bytes .../http/HttpURLConnectionImpl$Retry.class | Bin 0 -> 1377 bytes .../internal/http/HttpURLConnectionImpl.class | Bin 0 -> 14518 bytes .../okhttp/internal/http/HttpsEngine.class | Bin 0 -> 2567 bytes .../http/HttpsURLConnectionImpl$1.class | Bin 0 -> 285 bytes ...ectionImpl$HttpUrlConnectionDelegate.class | Bin 0 -> 1894 bytes .../http/HttpsURLConnectionImpl.class | Bin 0 -> 10545 bytes .../http/OkResponseCacheAdapter.class | Bin 0 -> 2009 bytes .../okhttp/internal/http/Policy.class | Bin 0 -> 428 bytes .../okhttp/internal/http/RawHeaders$1.class | Bin 0 -> 1025 bytes .../okhttp/internal/http/RawHeaders.class | Bin 0 -> 11676 bytes .../internal/http/RequestHeaders$1.class | Bin 0 -> 1577 bytes .../okhttp/internal/http/RequestHeaders.class | Bin 0 -> 8453 bytes .../internal/http/ResponseHeaders$1.class | Bin 0 -> 1645 bytes .../internal/http/ResponseHeaders.class | Bin 0 -> 12477 bytes .../internal/http/RetryableOutputStream.class | Bin 0 -> 1938 bytes .../okhttp/internal/http/RouteSelector.class | Bin 0 -> 6924 bytes .../okhttp/internal/http/SpdyTransport.class | Bin 0 -> 5184 bytes .../okhttp/internal/http/Transport.class | Bin 0 -> 671 bytes .../http/UnknownLengthHttpInputStream.class | Bin 0 -> 1631 bytes .../okhttp/internal/spdy/ErrorCode.class | Bin 0 -> 2693 bytes .../internal/spdy/FrameReader$Handler.class | Bin 0 -> 799 bytes .../okhttp/internal/spdy/FrameReader.class | Bin 0 -> 438 bytes .../okhttp/internal/spdy/FrameWriter.class | Bin 0 -> 955 bytes .../okhttp/internal/spdy/HeadersMode.class | Bin 0 -> 1608 bytes .../internal/spdy/Hpack$HeaderEntry.class | Bin 0 -> 929 bytes .../okhttp/internal/spdy/Hpack$Reader.class | Bin 0 -> 5906 bytes .../okhttp/internal/spdy/Hpack$Writer.class | Bin 0 -> 1681 bytes .../squareup/okhttp/internal/spdy/Hpack.class | Bin 0 -> 3116 bytes .../internal/spdy/Http20Draft06$Reader.class | Bin 0 -> 7293 bytes .../internal/spdy/Http20Draft06$Writer.class | Bin 0 -> 4656 bytes .../okhttp/internal/spdy/Http20Draft06.class | Bin 0 -> 2075 bytes .../spdy/IncomingStreamHandler$1.class | Bin 0 -> 974 bytes .../internal/spdy/IncomingStreamHandler.class | Bin 0 -> 586 bytes .../spdy/NameValueBlockReader$1.class | Bin 0 -> 1495 bytes .../spdy/NameValueBlockReader$2.class | Bin 0 -> 1094 bytes ...ckReader$FillableInflaterInputStream.class | Bin 0 -> 816 bytes .../internal/spdy/NameValueBlockReader.class | Bin 0 -> 3557 bytes .../squareup/okhttp/internal/spdy/Ping.class | Bin 0 -> 1433 bytes .../okhttp/internal/spdy/Settings.class | Bin 0 -> 3491 bytes .../okhttp/internal/spdy/Spdy3$Reader.class | Bin 0 -> 7039 bytes .../okhttp/internal/spdy/Spdy3$Writer.class | Bin 0 -> 6511 bytes .../squareup/okhttp/internal/spdy/Spdy3.class | Bin 0 -> 3656 bytes .../internal/spdy/SpdyConnection$1.class | Bin 0 -> 1233 bytes .../internal/spdy/SpdyConnection$2.class | Bin 0 -> 1111 bytes .../internal/spdy/SpdyConnection$3.class | Bin 0 -> 1396 bytes .../spdy/SpdyConnection$Builder.class | Bin 0 -> 3526 bytes .../spdy/SpdyConnection$Reader$1.class | Bin 0 -> 1703 bytes .../internal/spdy/SpdyConnection$Reader.class | Bin 0 -> 8667 bytes .../okhttp/internal/spdy/SpdyConnection.class | Bin 0 -> 14356 bytes .../okhttp/internal/spdy/SpdyStream$1.class | Bin 0 -> 249 bytes .../spdy/SpdyStream$SpdyDataInputStream.class | Bin 0 -> 5723 bytes .../SpdyStream$SpdyDataOutputStream.class | Bin 0 -> 4927 bytes .../okhttp/internal/spdy/SpdyStream.class | Bin 0 -> 10328 bytes .../okhttp/internal/spdy/Variant.class | Bin 0 -> 654 bytes .../tls/DistinguishedNameParser.class | Bin 0 -> 5095 bytes .../internal/tls/OkHostnameVerifier.class | Bin 0 -> 5083 bytes .../classes/org/apache/cordova/App$1.class | Bin 0 -> 843 bytes .../classes/org/apache/cordova/App$2.class | Bin 0 -> 691 bytes .../classes/org/apache/cordova/App$3.class | Bin 0 -> 680 bytes .../classes/org/apache/cordova/App$4.class | Bin 0 -> 691 bytes .../classes/org/apache/cordova/App$5.class | Bin 0 -> 1755 bytes .../classes/org/apache/cordova/App.class | Bin 0 -> 6374 bytes .../apache/cordova/AuthenticationToken.class | Bin 0 -> 776 bytes .../org/apache/cordova/BuildConfig.class | Bin 0 -> 345 bytes .../org/apache/cordova/CallbackContext.class | Bin 0 -> 3216 bytes .../classes/org/apache/cordova/Config.class | Bin 0 -> 2668 bytes .../org/apache/cordova/ConfigXmlParser.class | Bin 0 -> 5852 bytes .../apache/cordova/CordovaActivity$1.class | Bin 0 -> 1008 bytes .../apache/cordova/CordovaActivity$2.class | Bin 0 -> 1049 bytes .../apache/cordova/CordovaActivity$3.class | Bin 0 -> 1416 bytes .../apache/cordova/CordovaActivity$4$1.class | Bin 0 -> 1063 bytes .../apache/cordova/CordovaActivity$4.class | Bin 0 -> 1971 bytes .../apache/cordova/CordovaActivity$5$1.class | Bin 0 -> 782 bytes .../apache/cordova/CordovaActivity$5.class | Bin 0 -> 2770 bytes .../org/apache/cordova/CordovaActivity.class | Bin 0 -> 21487 bytes .../org/apache/cordova/CordovaArgs.class | Bin 0 -> 2561 bytes .../org/apache/cordova/CordovaBridge.class | Bin 0 -> 5124 bytes .../cordova/CordovaChromeClient$1.class | Bin 0 -> 1110 bytes .../cordova/CordovaChromeClient$2.class | Bin 0 -> 1089 bytes .../cordova/CordovaChromeClient$3.class | Bin 0 -> 1189 bytes .../cordova/CordovaChromeClient$4.class | Bin 0 -> 1112 bytes .../cordova/CordovaChromeClient$5.class | Bin 0 -> 1111 bytes .../cordova/CordovaChromeClient$6.class | Bin 0 -> 1091 bytes .../cordova/CordovaChromeClient$7.class | Bin 0 -> 1190 bytes .../cordova/CordovaChromeClient$8.class | Bin 0 -> 1441 bytes .../cordova/CordovaChromeClient$9.class | Bin 0 -> 1149 bytes .../apache/cordova/CordovaChromeClient.class | Bin 0 -> 10293 bytes .../org/apache/cordova/CordovaInterface.class | Bin 0 -> 501 bytes .../org/apache/cordova/CordovaPlugin.class | Bin 0 -> 3427 bytes .../apache/cordova/CordovaPreferences.class | Bin 0 -> 5602 bytes ...CordovaResourceApi$OpenForReadResult.class | Bin 0 -> 905 bytes .../apache/cordova/CordovaResourceApi.class | Bin 0 -> 11534 bytes .../org/apache/cordova/CordovaUriHelper.class | Bin 0 -> 2841 bytes .../org/apache/cordova/CordovaWebView$1.class | Bin 0 -> 941 bytes .../org/apache/cordova/CordovaWebView$2.class | Bin 0 -> 1282 bytes .../org/apache/cordova/CordovaWebView$3.class | Bin 0 -> 1469 bytes .../org/apache/cordova/CordovaWebView$4.class | Bin 0 -> 1268 bytes .../CordovaWebView$ActivityResult.class | Bin 0 -> 757 bytes .../cordova/CordovaWebView$Level16Apis.class | Bin 0 -> 759 bytes .../org/apache/cordova/CordovaWebView.class | Bin 0 -> 24487 bytes .../cordova/CordovaWebViewClient$1$1.class | Bin 0 -> 984 bytes .../cordova/CordovaWebViewClient$1.class | Bin 0 -> 1260 bytes .../apache/cordova/CordovaWebViewClient.class | Bin 0 -> 7367 bytes .../org/apache/cordova/DirectoryManager.class | Bin 0 -> 2643 bytes .../classes/org/apache/cordova/DroidGap.class | Bin 0 -> 389 bytes .../org/apache/cordova/ExifHelper.class | Bin 0 -> 3465 bytes .../org/apache/cordova/ExposedJsApi.class | Bin 0 -> 1362 bytes .../org/apache/cordova/FileHelper.class | Bin 0 -> 4098 bytes .../IceCreamCordovaWebViewClient.class | Bin 0 -> 3878 bytes .../org/apache/cordova/JSONUtils.class | Bin 0 -> 1079 bytes .../classes/org/apache/cordova/LOG.class | Bin 0 -> 3248 bytes .../LinearLayoutSoftKeyboardDetect.class | Bin 0 -> 2210 bytes .../cordova/NativeToJsMessageQueue$1.class | Bin 0 -> 255 bytes .../NativeToJsMessageQueue$BridgeMode.class | Bin 0 -> 1089 bytes .../NativeToJsMessageQueue$JsMessage.class | Bin 0 -> 3122 bytes ...ToJsMessageQueue$LoadUrlBridgeMode$1.class | Bin 0 -> 1426 bytes ...veToJsMessageQueue$LoadUrlBridgeMode.class | Bin 0 -> 1562 bytes ...essageQueue$OnlineEventsBridgeMode$1.class | Bin 0 -> 1496 bytes ...essageQueue$OnlineEventsBridgeMode$2.class | Bin 0 -> 1266 bytes ...sMessageQueue$OnlineEventsBridgeMode.class | Bin 0 -> 2433 bytes ...veToJsMessageQueue$PollingBridgeMode.class | Bin 0 -> 1041 bytes ...oJsMessageQueue$PrivateApiBridgeMode.class | Bin 0 -> 3053 bytes .../cordova/NativeToJsMessageQueue.class | Bin 0 -> 7772 bytes .../org/apache/cordova/PluginEntry.class | Bin 0 -> 1899 bytes .../org/apache/cordova/PluginManager.class | Bin 0 -> 9922 bytes .../apache/cordova/PluginResult$Status.class | Bin 0 -> 1657 bytes .../org/apache/cordova/PluginResult.class | Bin 0 -> 4933 bytes .../org/apache/cordova/ScrollEvent.class | Bin 0 -> 835 bytes .../apache/cordova/Whitelist$URLPattern.class | Bin 0 -> 2995 bytes .../org/apache/cordova/Whitelist.class | Bin 0 -> 2831 bytes .../android/CordovaLib/ant-build/proguard.txt | 0 platforms/android/CordovaLib/build.gradle | 54 + .../android/CordovaLib/project.properties | 16 + .../src/com/squareup/okhttp/Address.java | 140 + .../src/com/squareup/okhttp/Connection.java | 335 +++ .../com/squareup/okhttp/ConnectionPool.java | 274 ++ .../src/com/squareup/okhttp/Dispatcher.java | 86 + .../src/com/squareup/okhttp/Failure.java | 59 + .../squareup/okhttp/HttpResponseCache.java | 722 +++++ .../src/com/squareup/okhttp/Job.java | 232 ++ .../src/com/squareup/okhttp/MediaType.java | 120 + .../com/squareup/okhttp/OkAuthenticator.java | 123 + .../src/com/squareup/okhttp/OkHttpClient.java | 408 +++ .../com/squareup/okhttp/OkResponseCache.java | 56 + .../src/com/squareup/okhttp/Request.java | 284 ++ .../src/com/squareup/okhttp/Response.java | 290 ++ .../com/squareup/okhttp/ResponseSource.java | 37 + .../src/com/squareup/okhttp/Route.java | 91 + .../com/squareup/okhttp/RouteDatabase.java | 57 + .../com/squareup/okhttp/TunnelRequest.java | 75 + .../okhttp/internal/AbstractOutputStream.java | 45 + .../com/squareup/okhttp/internal/Base64.java | 164 ++ .../okhttp/internal/DiskLruCache.java | 926 ++++++ .../src/com/squareup/okhttp/internal/Dns.java | 33 + .../internal/FaultRecoveringOutputStream.java | 163 ++ .../okhttp/internal/NamedRunnable.java | 40 + .../squareup/okhttp/internal/Platform.java | 370 +++ .../okhttp/internal/StrictLineReader.java | 207 ++ .../com/squareup/okhttp/internal/Util.java | 394 +++ .../http/AbstractHttpInputStream.java | 107 + .../okhttp/internal/http/HeaderParser.java | 112 + .../internal/http/HttpAuthenticator.java | 166 ++ .../okhttp/internal/http/HttpDate.java | 88 + .../okhttp/internal/http/HttpEngine.java | 686 +++++ .../okhttp/internal/http/HttpTransport.java | 497 ++++ .../internal/http/HttpURLConnectionImpl.java | 590 ++++ .../okhttp/internal/http/HttpsEngine.java | 72 + .../internal/http/HttpsURLConnectionImpl.java | 366 +++ .../internal/http/OkResponseCacheAdapter.java | 57 + .../squareup/okhttp/internal/http/Policy.java | 49 + .../okhttp/internal/http/RawHeaders.java | 447 +++ .../okhttp/internal/http/RequestHeaders.java | 317 +++ .../okhttp/internal/http/ResponseHeaders.java | 512 ++++ .../internal/http/RetryableOutputStream.java | 75 + .../okhttp/internal/http/RouteSelector.java | 269 ++ .../okhttp/internal/http/SpdyTransport.java | 103 + .../okhttp/internal/http/Transport.java | 64 + .../http/UnknownLengthHttpInputStream.java | 63 + .../okhttp/internal/spdy/ErrorCode.java | 83 + .../okhttp/internal/spdy/FrameReader.java | 55 + .../okhttp/internal/spdy/FrameWriter.java | 43 + .../okhttp/internal/spdy/HeadersMode.java | 49 + .../squareup/okhttp/internal/spdy/Hpack.java | 387 +++ .../okhttp/internal/spdy/Http20Draft06.java | 385 +++ .../internal/spdy/IncomingStreamHandler.java | 36 + .../internal/spdy/NameValueBlockReader.java | 139 + .../squareup/okhttp/internal/spdy/Ping.java | 71 + .../okhttp/internal/spdy/Settings.java | 187 ++ .../squareup/okhttp/internal/spdy/Spdy3.java | 463 +++ .../okhttp/internal/spdy/SpdyConnection.java | 599 ++++ .../okhttp/internal/spdy/SpdyStream.java | 684 +++++ .../okhttp/internal/spdy/Variant.java | 37 + .../internal/tls/DistinguishedNameParser.java | 407 +++ .../internal/tls/OkHostnameVerifier.java | 194 ++ .../src/org/apache/cordova/App.java | 301 ++ .../apache/cordova/AuthenticationToken.java | 69 + .../org/apache/cordova/CallbackContext.java | 144 + .../src/org/apache/cordova/Config.java | 122 + .../org/apache/cordova/ConfigXmlParser.java | 181 ++ .../org/apache/cordova/CordovaActivity.java | 1063 +++++++ .../src/org/apache/cordova/CordovaArgs.java | 113 + .../src/org/apache/cordova/CordovaBridge.java | 183 ++ .../apache/cordova/CordovaChromeClient.java | 331 +++ .../org/apache/cordova/CordovaInterface.java | 72 + .../src/org/apache/cordova/CordovaPlugin.java | 201 ++ .../apache/cordova/CordovaPreferences.java | 175 ++ .../apache/cordova/CordovaResourceApi.java | 447 +++ .../org/apache/cordova/CordovaUriHelper.java | 86 + .../org/apache/cordova/CordovaWebView.java | 934 ++++++ .../apache/cordova/CordovaWebViewClient.java | 365 +++ .../org/apache/cordova/DirectoryManager.java | 162 ++ .../src/org/apache/cordova/DroidGap.java | 34 + .../src/org/apache/cordova/ExifHelper.java | 186 ++ .../src/org/apache/cordova/ExposedJsApi.java | 52 + .../src/org/apache/cordova/FileHelper.java | 163 ++ .../cordova/IceCreamCordovaWebViewClient.java | 107 + .../src/org/apache/cordova/JSONUtils.java | 43 + .../src/org/apache/cordova/LOG.java | 234 ++ .../LinearLayoutSoftKeyboardDetect.java | 105 + .../cordova/NativeToJsMessageQueue.java | 531 ++++ .../src/org/apache/cordova/PluginEntry.java | 89 + .../src/org/apache/cordova/PluginManager.java | 356 +++ .../src/org/apache/cordova/PluginResult.java | 179 ++ .../src/org/apache/cordova/ScrollEvent.java | 67 + .../src/org/apache/cordova/Whitelist.java | 170 ++ .../ant-build/AndroidManifest.cordova.xml | 14 + .../android/ant-build/AndroidManifest.xml.d | 2 + .../ant-build/CordovaApp-debug-unaligned.apk | Bin 0 -> 3888849 bytes .../CordovaApp-debug-unaligned.apk.d | 4 + .../android/ant-build/CordovaApp-debug.apk | Bin 0 -> 3888941 bytes .../ant-build/CordovaApp-release-unsigned.apk | Bin 0 -> 3881709 bytes .../CordovaApp-release-unsigned.apk.d | 4 + platforms/android/ant-build/CordovaApp.ap_ | Bin 0 -> 3730852 bytes platforms/android/ant-build/CordovaApp.ap_.d | 128 + platforms/android/ant-build/R.txt | 6 + platforms/android/ant-build/build.prop | 10 + platforms/android/ant-build/classes.dex | Bin 0 -> 398560 bytes platforms/android/ant-build/classes.dex.d | 9 + .../com/phonegap/helloworld/BuildConfig.class | Bin 0 -> 355 bytes .../com/phonegap/helloworld/CordovaApp.class | Bin 0 -> 610 bytes .../com/phonegap/helloworld/R$attr.class | Bin 0 -> 355 bytes .../com/phonegap/helloworld/R$drawable.class | Bin 0 -> 445 bytes .../com/phonegap/helloworld/R$string.class | Bin 0 -> 487 bytes .../com/phonegap/helloworld/R$xml.class | Bin 0 -> 402 bytes .../classes/com/phonegap/helloworld/R.class | Bin 0 -> 517 bytes ...asses-69c1fe24b407f93fb08e9f66f354ee73.jar | Bin 0 -> 150305 bytes ...asses-703f86d81f0ed180098d872ee1ccf45c.jar | Bin 0 -> 150305 bytes platforms/android/ant-build/proguard.txt | 3 + .../ant-build/res/drawable-hdpi/icon.png | Bin 0 -> 7604 bytes .../res/drawable-land-hdpi/screen.png | Bin 0 -> 216014 bytes .../res/drawable-land-ldpi/screen.png | Bin 0 -> 41538 bytes .../res/drawable-land-mdpi/screen.png | Bin 0 -> 90490 bytes .../res/drawable-land-xhdpi/screen.png | Bin 0 -> 488469 bytes .../res/drawable-port-hdpi/screen.png | Bin 0 -> 220338 bytes .../res/drawable-port-ldpi/screen.png | Bin 0 -> 41064 bytes .../res/drawable-port-mdpi/screen.png | Bin 0 -> 92429 bytes .../res/drawable-port-xhdpi/screen.png | Bin 0 -> 501006 bytes .../ant-build/res/drawable-xxhdpi/icon.png | Bin 0 -> 20540 bytes .../android/ant-build/res/drawable/icon.png | Bin 0 -> 6814 bytes platforms/android/assets/_where-is-www.txt | 3 + platforms/android/assets/www/cordova.js | 1938 +++++++++++++ .../android/assets/www/cordova_plugins.js | 7 + .../assets/www/css/bootstrap-theme.min.css | 5 + .../android/assets/www/css/bootstrap.min.css | 7 + .../assets/www/css/font-awesome.min.css | 4 + platforms/android/assets/www/css/index.css | 96 + .../android/assets/www/fonts/FontAwesome.otf | Bin 0 -> 93888 bytes .../assets/www/fonts/fontawesome-webfont.eot | Bin 0 -> 60767 bytes .../assets/www/fonts/fontawesome-webfont.svg | 565 ++++ .../assets/www/fonts/fontawesome-webfont.ttf | Bin 0 -> 122092 bytes .../assets/www/fonts/fontawesome-webfont.woff | Bin 0 -> 71508 bytes .../www/fonts/fontawesome-webfont.woff2 | Bin 0 -> 56780 bytes .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 ++ .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes platforms/android/assets/www/icon.png | Bin 0 -> 11401 bytes platforms/android/assets/www/img/logo.png | Bin 0 -> 29632 bytes platforms/android/assets/www/index.html | 75 + platforms/android/assets/www/index.json | 72 + .../android/assets/www/js/bootstrap.min.js | 7 + platforms/android/assets/www/js/index.js | 159 ++ platforms/android/assets/www/res/.pgbomit | 0 .../www/res/icon/android/icon-36-ldpi.png | Bin 0 -> 3383 bytes .../www/res/icon/android/icon-48-mdpi.png | Bin 0 -> 4681 bytes .../www/res/icon/android/icon-72-hdpi.png | Bin 0 -> 7839 bytes .../www/res/icon/android/icon-96-xhdpi.png | Bin 0 -> 11483 bytes .../www/res/icon/bada-wac/icon-48-type5.png | Bin 0 -> 4766 bytes .../www/res/icon/bada-wac/icon-50-type3.png | Bin 0 -> 4998 bytes .../www/res/icon/bada-wac/icon-80-type4.png | Bin 0 -> 9217 bytes .../assets/www/res/icon/bada/icon-128.png | Bin 0 -> 16334 bytes .../www/res/icon/blackberry/icon-80.png | Bin 0 -> 9217 bytes .../assets/www/res/icon/ios/icon-57-2x.png | Bin 0 -> 14643 bytes .../assets/www/res/icon/ios/icon-57.png | Bin 0 -> 6177 bytes .../assets/www/res/icon/ios/icon-72-2x.png | Bin 0 -> 19336 bytes .../assets/www/res/icon/ios/icon-72.png | Bin 0 -> 7839 bytes .../assets/www/res/icon/tizen/icon-128.png | Bin 0 -> 11401 bytes .../assets/www/res/icon/webos/icon-64.png | Bin 0 -> 6690 bytes .../res/icon/windows-phone/icon-173-tile.png | Bin 0 -> 21147 bytes .../www/res/icon/windows-phone/icon-48.png | Bin 0 -> 4653 bytes .../res/icon/windows-phone/icon-62-tile.png | Bin 0 -> 6207 bytes .../screen/android/screen-hdpi-landscape.png | Bin 0 -> 45248 bytes .../screen/android/screen-hdpi-portrait.png | Bin 0 -> 46644 bytes .../screen/android/screen-ldpi-landscape.png | Bin 0 -> 15112 bytes .../screen/android/screen-ldpi-portrait.png | Bin 0 -> 14941 bytes .../screen/android/screen-mdpi-landscape.png | Bin 0 -> 28912 bytes .../screen/android/screen-mdpi-portrait.png | Bin 0 -> 29381 bytes .../screen/android/screen-xhdpi-landscape.png | Bin 0 -> 77189 bytes .../screen/android/screen-xhdpi-portrait.png | Bin 0 -> 78744 bytes .../www/res/screen/bada-wac/screen-type3.png | Bin 0 -> 29372 bytes .../www/res/screen/bada-wac/screen-type4.png | Bin 0 -> 46647 bytes .../www/res/screen/bada-wac/screen-type5.png | Bin 0 -> 18937 bytes .../www/res/screen/bada/screen-portrait.png | Bin 0 -> 46647 bytes .../www/res/screen/blackberry/screen-225.png | Bin 0 -> 29556 bytes .../screen/ios/screen-ipad-landscape-2x.png | Bin 0 -> 87242 bytes .../res/screen/ios/screen-ipad-landscape.png | Bin 0 -> 86796 bytes .../screen/ios/screen-ipad-portrait-2x.png | Bin 0 -> 85806 bytes .../res/screen/ios/screen-ipad-portrait.png | Bin 0 -> 68785 bytes .../screen/ios/screen-iphone-landscape-2x.png | Bin 0 -> 72319 bytes .../screen/ios/screen-iphone-landscape.png | Bin 0 -> 30210 bytes .../screen/ios/screen-iphone-portrait-2x.png | Bin 0 -> 70677 bytes .../ios/screen-iphone-portrait-568h-2x.png | Bin 0 -> 85308 bytes .../res/screen/ios/screen-iphone-portrait.png | Bin 0 -> 29372 bytes .../assets/www/res/screen/tizen/README.md | 3 + .../assets/www/res/screen/webos/screen-64.png | Bin 0 -> 6263 bytes .../screen/windows-phone/screen-portrait.jpg | Bin 0 -> 20813 bytes platforms/android/assets/www/spec.html | 68 + platforms/android/assets/www/spec/helper.js | 33 + platforms/android/assets/www/spec/index.js | 67 + .../www/spec/lib/jasmine-1.2.0/MIT.LICENSE | 20 + .../spec/lib/jasmine-1.2.0/jasmine-html.js | 616 ++++ .../www/spec/lib/jasmine-1.2.0/jasmine.css | 81 + .../www/spec/lib/jasmine-1.2.0/jasmine.js | 2529 +++++++++++++++++ platforms/android/build.gradle | 94 + platforms/android/cordova/android_sdk_version | 29 + platforms/android/cordova/build | 41 + platforms/android/cordova/build.bat | 26 + platforms/android/cordova/check_reqs | 31 + platforms/android/cordova/clean | 44 + platforms/android/cordova/clean.bat | 26 + platforms/android/cordova/defaults.xml | 26 + .../cordova/lib/android_sdk_version.js | 65 + platforms/android/cordova/lib/appinfo.js | 41 + platforms/android/cordova/lib/build.js | 385 +++ platforms/android/cordova/lib/check_reqs.js | 184 ++ platforms/android/cordova/lib/device.js | 90 + platforms/android/cordova/lib/emulator.js | 328 +++ platforms/android/cordova/lib/exec.js | 41 + platforms/android/cordova/lib/install-device | 42 + .../android/cordova/lib/install-device.bat | 26 + .../android/cordova/lib/install-emulator | 38 + .../android/cordova/lib/install-emulator.bat | 26 + platforms/android/cordova/lib/list-devices | 33 + .../android/cordova/lib/list-devices.bat | 26 + .../android/cordova/lib/list-emulator-images | 32 + .../cordova/lib/list-emulator-images.bat | 26 + .../cordova/lib/list-started-emulators | 32 + .../cordova/lib/list-started-emulators.bat | 26 + platforms/android/cordova/lib/log.js | 57 + platforms/android/cordova/lib/run.js | 139 + platforms/android/cordova/lib/spawn.js | 49 + platforms/android/cordova/lib/start-emulator | 39 + .../android/cordova/lib/start-emulator.bat | 26 + platforms/android/cordova/log | 36 + platforms/android/cordova/log.bat | 26 + .../cordova/node_modules/q/CONTRIBUTING.md | 40 + .../android/cordova/node_modules/q/LICENSE | 19 + .../android/cordova/node_modules/q/README.md | 813 ++++++ .../q/benchmark/compare-with-callbacks.js | 71 + .../node_modules/q/benchmark/scenarios.js | 36 + .../cordova/node_modules/q/package.json | 93 + platforms/android/cordova/node_modules/q/q.js | 1937 +++++++++++++ .../android/cordova/node_modules/q/queue.js | 35 + .../node_modules/shelljs/.documentup.json | 6 + .../cordova/node_modules/shelljs/.jshintrc | 7 + .../cordova/node_modules/shelljs/.npmignore | 2 + .../cordova/node_modules/shelljs/.travis.yml | 5 + .../cordova/node_modules/shelljs/LICENSE | 26 + .../cordova/node_modules/shelljs/README.md | 552 ++++ .../cordova/node_modules/shelljs/bin/shjs | 51 + .../cordova/node_modules/shelljs/global.js | 3 + .../cordova/node_modules/shelljs/make.js | 47 + .../cordova/node_modules/shelljs/package.json | 48 + .../shelljs/scripts/generate-docs.js | 21 + .../node_modules/shelljs/scripts/run-tests.js | 50 + .../cordova/node_modules/shelljs/shell.js | 153 + .../cordova/node_modules/shelljs/src/cat.js | 43 + .../cordova/node_modules/shelljs/src/cd.js | 19 + .../cordova/node_modules/shelljs/src/chmod.js | 208 ++ .../node_modules/shelljs/src/common.js | 189 ++ .../cordova/node_modules/shelljs/src/cp.js | 200 ++ .../cordova/node_modules/shelljs/src/dirs.js | 191 ++ .../cordova/node_modules/shelljs/src/echo.js | 20 + .../cordova/node_modules/shelljs/src/error.js | 10 + .../cordova/node_modules/shelljs/src/exec.js | 181 ++ .../cordova/node_modules/shelljs/src/find.js | 51 + .../cordova/node_modules/shelljs/src/grep.js | 52 + .../cordova/node_modules/shelljs/src/ls.js | 126 + .../cordova/node_modules/shelljs/src/mkdir.js | 68 + .../cordova/node_modules/shelljs/src/mv.js | 80 + .../cordova/node_modules/shelljs/src/popd.js | 1 + .../cordova/node_modules/shelljs/src/pushd.js | 1 + .../cordova/node_modules/shelljs/src/pwd.js | 11 + .../cordova/node_modules/shelljs/src/rm.js | 145 + .../cordova/node_modules/shelljs/src/sed.js | 43 + .../node_modules/shelljs/src/tempdir.js | 56 + .../cordova/node_modules/shelljs/src/test.js | 85 + .../cordova/node_modules/shelljs/src/to.js | 29 + .../cordova/node_modules/shelljs/src/toEnd.js | 29 + .../cordova/node_modules/shelljs/src/which.js | 79 + .../cordova/node_modules/which/LICENSE | 23 + .../cordova/node_modules/which/README.md | 5 + .../cordova/node_modules/which/bin/which | 14 + .../cordova/node_modules/which/package.json | 31 + .../cordova/node_modules/which/which.js | 104 + platforms/android/cordova/run | 37 + platforms/android/cordova/run.bat | 26 + platforms/android/cordova/version | 25 + platforms/android/cordova/version.bat | 26 + platforms/android/custom_rules.xml | 22 + platforms/android/platform_www/cordova.js | 1938 +++++++++++++ platforms/android/project.properties | 14 + platforms/android/res/drawable-hdpi/icon.png | Bin 0 -> 7839 bytes .../android/res/drawable-land-hdpi/screen.png | Bin 0 -> 218302 bytes .../android/res/drawable-land-ldpi/screen.png | Bin 0 -> 42616 bytes .../android/res/drawable-land-mdpi/screen.png | Bin 0 -> 92347 bytes .../res/drawable-land-xhdpi/screen.png | Bin 0 -> 489604 bytes .../android/res/drawable-port-hdpi/screen.png | Bin 0 -> 222148 bytes .../android/res/drawable-port-ldpi/screen.png | Bin 0 -> 42034 bytes .../android/res/drawable-port-mdpi/screen.png | Bin 0 -> 90555 bytes .../res/drawable-port-xhdpi/screen.png | Bin 0 -> 504508 bytes .../android/res/drawable-xxhdpi/icon.png | Bin 0 -> 19336 bytes platforms/android/res/drawable/icon.png | Bin 0 -> 7685 bytes platforms/android/res/values/strings.xml | 6 + platforms/android/res/xml/config.xml | 71 + platforms/android/settings.gradle | 18 + .../src/com/cadoles/momo/CordovaApp.java | 35 + .../com/phonegap/helloworld/CordovaApp.java | 35 + plugins/android.json | 11 + www/css/animations.css | 1297 +++++++++ www/css/bootstrap-theme.min.css | 5 + www/css/bootstrap.min.css | 7 + www/css/font-awesome.min.css | 4 + www/css/index.css | 105 + www/fonts/FontAwesome.otf | Bin 0 -> 93888 bytes www/fonts/fontawesome-webfont.eot | Bin 0 -> 60767 bytes www/fonts/fontawesome-webfont.svg | 565 ++++ www/fonts/fontawesome-webfont.ttf | Bin 0 -> 122092 bytes www/fonts/fontawesome-webfont.woff | Bin 0 -> 71508 bytes www/fonts/fontawesome-webfont.woff2 | Bin 0 -> 56780 bytes www/fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes www/fonts/glyphicons-halflings-regular.svg | 288 ++ www/fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes www/fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes www/fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes www/icon.png | Bin 0 -> 11401 bytes www/img/logo.png | Bin 0 -> 29632 bytes www/index.html | 78 + www/index.json | 72 + www/js/bootstrap.min.js | 7 + www/js/index.js | 159 ++ www/js/pagetransitions.js | 398 +++ www/res/.pgbomit | 0 www/res/icon/android/icon-36-ldpi.png | Bin 0 -> 3383 bytes www/res/icon/android/icon-48-mdpi.png | Bin 0 -> 4681 bytes www/res/icon/android/icon-72-hdpi.png | Bin 0 -> 7839 bytes www/res/icon/android/icon-96-xhdpi.png | Bin 0 -> 11483 bytes www/res/icon/bada-wac/icon-48-type5.png | Bin 0 -> 4766 bytes www/res/icon/bada-wac/icon-50-type3.png | Bin 0 -> 4998 bytes www/res/icon/bada-wac/icon-80-type4.png | Bin 0 -> 9217 bytes www/res/icon/bada/icon-128.png | Bin 0 -> 16334 bytes www/res/icon/blackberry/icon-80.png | Bin 0 -> 9217 bytes www/res/icon/ios/icon-57-2x.png | Bin 0 -> 14643 bytes www/res/icon/ios/icon-57.png | Bin 0 -> 6177 bytes www/res/icon/ios/icon-72-2x.png | Bin 0 -> 19336 bytes www/res/icon/ios/icon-72.png | Bin 0 -> 7839 bytes www/res/icon/tizen/icon-128.png | Bin 0 -> 11401 bytes www/res/icon/webos/icon-64.png | Bin 0 -> 6690 bytes www/res/icon/windows-phone/icon-173-tile.png | Bin 0 -> 21147 bytes www/res/icon/windows-phone/icon-48.png | Bin 0 -> 4653 bytes www/res/icon/windows-phone/icon-62-tile.png | Bin 0 -> 6207 bytes .../screen/android/screen-hdpi-landscape.png | Bin 0 -> 45248 bytes .../screen/android/screen-hdpi-portrait.png | Bin 0 -> 46644 bytes .../screen/android/screen-ldpi-landscape.png | Bin 0 -> 15112 bytes .../screen/android/screen-ldpi-portrait.png | Bin 0 -> 14941 bytes .../screen/android/screen-mdpi-landscape.png | Bin 0 -> 28912 bytes .../screen/android/screen-mdpi-portrait.png | Bin 0 -> 29381 bytes .../screen/android/screen-xhdpi-landscape.png | Bin 0 -> 77189 bytes .../screen/android/screen-xhdpi-portrait.png | Bin 0 -> 78744 bytes www/res/screen/bada-wac/screen-type3.png | Bin 0 -> 29372 bytes www/res/screen/bada-wac/screen-type4.png | Bin 0 -> 46647 bytes www/res/screen/bada-wac/screen-type5.png | Bin 0 -> 18937 bytes www/res/screen/bada/screen-portrait.png | Bin 0 -> 46647 bytes www/res/screen/blackberry/screen-225.png | Bin 0 -> 29556 bytes .../screen/ios/screen-ipad-landscape-2x.png | Bin 0 -> 87242 bytes www/res/screen/ios/screen-ipad-landscape.png | Bin 0 -> 86796 bytes .../screen/ios/screen-ipad-portrait-2x.png | Bin 0 -> 85806 bytes www/res/screen/ios/screen-ipad-portrait.png | Bin 0 -> 68785 bytes .../screen/ios/screen-iphone-landscape-2x.png | Bin 0 -> 72319 bytes .../screen/ios/screen-iphone-landscape.png | Bin 0 -> 30210 bytes .../screen/ios/screen-iphone-portrait-2x.png | Bin 0 -> 70677 bytes .../ios/screen-iphone-portrait-568h-2x.png | Bin 0 -> 85308 bytes www/res/screen/ios/screen-iphone-portrait.png | Bin 0 -> 29372 bytes www/res/screen/tizen/README.md | 3 + www/res/screen/webos/screen-64.png | Bin 0 -> 6263 bytes .../screen/windows-phone/screen-portrait.jpg | Bin 0 -> 20813 bytes www/spec.html | 68 + www/spec/helper.js | 33 + www/spec/index.js | 67 + www/spec/lib/jasmine-1.2.0/MIT.LICENSE | 20 + www/spec/lib/jasmine-1.2.0/jasmine-html.js | 616 ++++ www/spec/lib/jasmine-1.2.0/jasmine.css | 81 + www/spec/lib/jasmine-1.2.0/jasmine.js | 2529 +++++++++++++++++ 607 files changed, 45692 insertions(+) create mode 100644 .cordova/config.json create mode 100644 .gitignore create mode 100644 config.xml create mode 100644 hooks/README.md create mode 100644 platforms/android/.gitignore create mode 100644 platforms/android/.project create mode 100644 platforms/android/AndroidManifest.xml create mode 100644 platforms/android/CordovaLib/.project create mode 100755 platforms/android/CordovaLib/AndroidManifest.xml create mode 100644 platforms/android/CordovaLib/ant-build/AndroidManifest.cordova.xml create mode 100644 platforms/android/CordovaLib/ant-build/AndroidManifest.xml.d create mode 100644 platforms/android/CordovaLib/ant-build/build.prop create mode 100644 platforms/android/CordovaLib/ant-build/classes.jar create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Address.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Connection.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/ConnectionPool$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/ConnectionPool$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/ConnectionPool.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Dispatcher$RealResponseBody.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Dispatcher.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Failure$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Failure$Builder.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Failure.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$3.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$CacheRequestImpl$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$CacheRequestImpl.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$Entry.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$EntryCacheResponse.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$EntrySecureCacheResponse.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Job.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/MediaType.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkAuthenticator$Challenge.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkAuthenticator$Credential.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkAuthenticator.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkHttpClient$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkHttpClient.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkResponseCache.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Body$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Body$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Body.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Builder.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$Body.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$Builder.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$Receiver.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/ResponseSource.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Route.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/RouteDatabase.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/TunnelRequest.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/AbstractOutputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Base64.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache$Editor$FaultHidingOutputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache$Editor.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache$Entry.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache$Snapshot.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Dns$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Dns.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/FaultRecoveringOutputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/NamedRunnable.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$Android23.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$Android41.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$JdkWithJettyNpnPlatform.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$JettyNpnProvider.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/StrictLineReader$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/StrictLineReader.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Util$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Util.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/AbstractHttpInputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HeaderParser$CacheControlHandler.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HeaderParser.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpAuthenticator$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpAuthenticator.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpDate$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpDate.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpEngine$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpEngine.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport$ChunkedInputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport$ChunkedOutputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport$FixedLengthInputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport$FixedLengthOutputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpURLConnectionImpl$Retry.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsEngine.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl$HttpUrlConnectionDelegate.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/OkResponseCacheAdapter.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/Policy.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RawHeaders$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RawHeaders.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RequestHeaders$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RequestHeaders.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/ResponseHeaders$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/ResponseHeaders.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RetryableOutputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RouteSelector.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/SpdyTransport.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/Transport.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/UnknownLengthHttpInputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/ErrorCode.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/FrameReader$Handler.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/FrameReader.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/FrameWriter.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/HeadersMode.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Hpack$HeaderEntry.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Hpack$Reader.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Hpack$Writer.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Hpack.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Http20Draft06$Reader.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Http20Draft06$Writer.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Http20Draft06.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/IncomingStreamHandler$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/IncomingStreamHandler.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader$FillableInflaterInputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Ping.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Settings.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Spdy3$Reader.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Spdy3$Writer.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Spdy3.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$3.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$Builder.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$Reader$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$Reader.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyStream$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyStream$SpdyDataInputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyStream$SpdyDataOutputStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyStream.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Variant.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/tls/DistinguishedNameParser.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/tls/OkHostnameVerifier.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$3.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$4.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$5.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/AuthenticationToken.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/BuildConfig.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CallbackContext.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/Config.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/ConfigXmlParser.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$3.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$4$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$4.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$5$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$5.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaArgs.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaBridge.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$3.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$4.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$5.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$6.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$7.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$8.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$9.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaInterface.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaPlugin.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaPreferences.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaResourceApi$OpenForReadResult.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaResourceApi.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaUriHelper.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$3.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$4.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$ActivityResult.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$Level16Apis.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebViewClient$1$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebViewClient$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebViewClient.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/DirectoryManager.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/DroidGap.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/ExifHelper.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/ExposedJsApi.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/FileHelper.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/IceCreamCordovaWebViewClient.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/JSONUtils.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/LOG.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/LinearLayoutSoftKeyboardDetect.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$BridgeMode.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$JsMessage.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$LoadUrlBridgeMode$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$LoadUrlBridgeMode.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$OnlineEventsBridgeMode$1.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$OnlineEventsBridgeMode$2.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$OnlineEventsBridgeMode.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$PollingBridgeMode.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$PrivateApiBridgeMode.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/PluginEntry.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/PluginManager.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/PluginResult$Status.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/PluginResult.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/ScrollEvent.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/Whitelist$URLPattern.class create mode 100644 platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/Whitelist.class create mode 100644 platforms/android/CordovaLib/ant-build/proguard.txt create mode 100644 platforms/android/CordovaLib/build.gradle create mode 100644 platforms/android/CordovaLib/project.properties create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/Address.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/Connection.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/ConnectionPool.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/Dispatcher.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/Failure.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/HttpResponseCache.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/Job.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/MediaType.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/OkAuthenticator.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/OkHttpClient.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/OkResponseCache.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/Request.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/Response.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/ResponseSource.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/Route.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/RouteDatabase.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/TunnelRequest.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/AbstractOutputStream.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Base64.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/DiskLruCache.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Dns.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/FaultRecoveringOutputStream.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/NamedRunnable.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Platform.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/StrictLineReader.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Util.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/AbstractHttpInputStream.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HeaderParser.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpAuthenticator.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpDate.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpEngine.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpTransport.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpsEngine.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/OkResponseCacheAdapter.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/Policy.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RawHeaders.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RequestHeaders.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/ResponseHeaders.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RetryableOutputStream.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RouteSelector.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/SpdyTransport.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/Transport.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/UnknownLengthHttpInputStream.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/ErrorCode.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/FrameReader.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/FrameWriter.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/HeadersMode.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Hpack.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Http20Draft06.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/IncomingStreamHandler.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/NameValueBlockReader.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Ping.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Settings.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Spdy3.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/SpdyConnection.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/SpdyStream.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Variant.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/tls/DistinguishedNameParser.java create mode 100755 platforms/android/CordovaLib/src/com/squareup/okhttp/internal/tls/OkHostnameVerifier.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/App.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/Config.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/CordovaChromeClient.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/CordovaInterface.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/CordovaPlugin.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/CordovaPreferences.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/CordovaResourceApi.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/CordovaUriHelper.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebView.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewClient.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/DirectoryManager.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/DroidGap.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/ExifHelper.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/ExposedJsApi.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/FileHelper.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/IceCreamCordovaWebViewClient.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/JSONUtils.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/LOG.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/LinearLayoutSoftKeyboardDetect.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/NativeToJsMessageQueue.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/PluginEntry.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/PluginManager.java create mode 100755 platforms/android/CordovaLib/src/org/apache/cordova/PluginResult.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/ScrollEvent.java create mode 100644 platforms/android/CordovaLib/src/org/apache/cordova/Whitelist.java create mode 100644 platforms/android/ant-build/AndroidManifest.cordova.xml create mode 100644 platforms/android/ant-build/AndroidManifest.xml.d create mode 100644 platforms/android/ant-build/CordovaApp-debug-unaligned.apk create mode 100644 platforms/android/ant-build/CordovaApp-debug-unaligned.apk.d create mode 100644 platforms/android/ant-build/CordovaApp-debug.apk create mode 100644 platforms/android/ant-build/CordovaApp-release-unsigned.apk create mode 100644 platforms/android/ant-build/CordovaApp-release-unsigned.apk.d create mode 100644 platforms/android/ant-build/CordovaApp.ap_ create mode 100644 platforms/android/ant-build/CordovaApp.ap_.d create mode 100644 platforms/android/ant-build/R.txt create mode 100644 platforms/android/ant-build/build.prop create mode 100644 platforms/android/ant-build/classes.dex create mode 100644 platforms/android/ant-build/classes.dex.d create mode 100644 platforms/android/ant-build/classes/com/phonegap/helloworld/BuildConfig.class create mode 100644 platforms/android/ant-build/classes/com/phonegap/helloworld/CordovaApp.class create mode 100644 platforms/android/ant-build/classes/com/phonegap/helloworld/R$attr.class create mode 100644 platforms/android/ant-build/classes/com/phonegap/helloworld/R$drawable.class create mode 100644 platforms/android/ant-build/classes/com/phonegap/helloworld/R$string.class create mode 100644 platforms/android/ant-build/classes/com/phonegap/helloworld/R$xml.class create mode 100644 platforms/android/ant-build/classes/com/phonegap/helloworld/R.class create mode 100644 platforms/android/ant-build/dexedLibs/classes-69c1fe24b407f93fb08e9f66f354ee73.jar create mode 100644 platforms/android/ant-build/dexedLibs/classes-703f86d81f0ed180098d872ee1ccf45c.jar create mode 100644 platforms/android/ant-build/proguard.txt create mode 100644 platforms/android/ant-build/res/drawable-hdpi/icon.png create mode 100644 platforms/android/ant-build/res/drawable-land-hdpi/screen.png create mode 100644 platforms/android/ant-build/res/drawable-land-ldpi/screen.png create mode 100644 platforms/android/ant-build/res/drawable-land-mdpi/screen.png create mode 100644 platforms/android/ant-build/res/drawable-land-xhdpi/screen.png create mode 100644 platforms/android/ant-build/res/drawable-port-hdpi/screen.png create mode 100644 platforms/android/ant-build/res/drawable-port-ldpi/screen.png create mode 100644 platforms/android/ant-build/res/drawable-port-mdpi/screen.png create mode 100644 platforms/android/ant-build/res/drawable-port-xhdpi/screen.png create mode 100644 platforms/android/ant-build/res/drawable-xxhdpi/icon.png create mode 100644 platforms/android/ant-build/res/drawable/icon.png create mode 100644 platforms/android/assets/_where-is-www.txt create mode 100644 platforms/android/assets/www/cordova.js create mode 100644 platforms/android/assets/www/cordova_plugins.js create mode 100644 platforms/android/assets/www/css/bootstrap-theme.min.css create mode 100644 platforms/android/assets/www/css/bootstrap.min.css create mode 100644 platforms/android/assets/www/css/font-awesome.min.css create mode 100644 platforms/android/assets/www/css/index.css create mode 100644 platforms/android/assets/www/fonts/FontAwesome.otf create mode 100644 platforms/android/assets/www/fonts/fontawesome-webfont.eot create mode 100644 platforms/android/assets/www/fonts/fontawesome-webfont.svg create mode 100644 platforms/android/assets/www/fonts/fontawesome-webfont.ttf create mode 100644 platforms/android/assets/www/fonts/fontawesome-webfont.woff create mode 100644 platforms/android/assets/www/fonts/fontawesome-webfont.woff2 create mode 100644 platforms/android/assets/www/fonts/glyphicons-halflings-regular.eot create mode 100644 platforms/android/assets/www/fonts/glyphicons-halflings-regular.svg create mode 100644 platforms/android/assets/www/fonts/glyphicons-halflings-regular.ttf create mode 100644 platforms/android/assets/www/fonts/glyphicons-halflings-regular.woff create mode 100644 platforms/android/assets/www/fonts/glyphicons-halflings-regular.woff2 create mode 100644 platforms/android/assets/www/icon.png create mode 100644 platforms/android/assets/www/img/logo.png create mode 100644 platforms/android/assets/www/index.html create mode 100644 platforms/android/assets/www/index.json create mode 100644 platforms/android/assets/www/js/bootstrap.min.js create mode 100644 platforms/android/assets/www/js/index.js create mode 100644 platforms/android/assets/www/res/.pgbomit create mode 100644 platforms/android/assets/www/res/icon/android/icon-36-ldpi.png create mode 100644 platforms/android/assets/www/res/icon/android/icon-48-mdpi.png create mode 100644 platforms/android/assets/www/res/icon/android/icon-72-hdpi.png create mode 100644 platforms/android/assets/www/res/icon/android/icon-96-xhdpi.png create mode 100644 platforms/android/assets/www/res/icon/bada-wac/icon-48-type5.png create mode 100755 platforms/android/assets/www/res/icon/bada-wac/icon-50-type3.png create mode 100644 platforms/android/assets/www/res/icon/bada-wac/icon-80-type4.png create mode 100644 platforms/android/assets/www/res/icon/bada/icon-128.png create mode 100644 platforms/android/assets/www/res/icon/blackberry/icon-80.png create mode 100644 platforms/android/assets/www/res/icon/ios/icon-57-2x.png create mode 100644 platforms/android/assets/www/res/icon/ios/icon-57.png create mode 100644 platforms/android/assets/www/res/icon/ios/icon-72-2x.png create mode 100644 platforms/android/assets/www/res/icon/ios/icon-72.png create mode 100644 platforms/android/assets/www/res/icon/tizen/icon-128.png create mode 100644 platforms/android/assets/www/res/icon/webos/icon-64.png create mode 100644 platforms/android/assets/www/res/icon/windows-phone/icon-173-tile.png create mode 100644 platforms/android/assets/www/res/icon/windows-phone/icon-48.png create mode 100644 platforms/android/assets/www/res/icon/windows-phone/icon-62-tile.png create mode 100644 platforms/android/assets/www/res/screen/android/screen-hdpi-landscape.png create mode 100644 platforms/android/assets/www/res/screen/android/screen-hdpi-portrait.png create mode 100644 platforms/android/assets/www/res/screen/android/screen-ldpi-landscape.png create mode 100644 platforms/android/assets/www/res/screen/android/screen-ldpi-portrait.png create mode 100644 platforms/android/assets/www/res/screen/android/screen-mdpi-landscape.png create mode 100644 platforms/android/assets/www/res/screen/android/screen-mdpi-portrait.png create mode 100644 platforms/android/assets/www/res/screen/android/screen-xhdpi-landscape.png create mode 100644 platforms/android/assets/www/res/screen/android/screen-xhdpi-portrait.png create mode 100644 platforms/android/assets/www/res/screen/bada-wac/screen-type3.png create mode 100644 platforms/android/assets/www/res/screen/bada-wac/screen-type4.png create mode 100755 platforms/android/assets/www/res/screen/bada-wac/screen-type5.png create mode 100644 platforms/android/assets/www/res/screen/bada/screen-portrait.png create mode 100644 platforms/android/assets/www/res/screen/blackberry/screen-225.png create mode 100644 platforms/android/assets/www/res/screen/ios/screen-ipad-landscape-2x.png create mode 100644 platforms/android/assets/www/res/screen/ios/screen-ipad-landscape.png create mode 100644 platforms/android/assets/www/res/screen/ios/screen-ipad-portrait-2x.png create mode 100644 platforms/android/assets/www/res/screen/ios/screen-ipad-portrait.png create mode 100644 platforms/android/assets/www/res/screen/ios/screen-iphone-landscape-2x.png create mode 100644 platforms/android/assets/www/res/screen/ios/screen-iphone-landscape.png create mode 100644 platforms/android/assets/www/res/screen/ios/screen-iphone-portrait-2x.png create mode 100644 platforms/android/assets/www/res/screen/ios/screen-iphone-portrait-568h-2x.png create mode 100644 platforms/android/assets/www/res/screen/ios/screen-iphone-portrait.png create mode 100644 platforms/android/assets/www/res/screen/tizen/README.md create mode 100644 platforms/android/assets/www/res/screen/webos/screen-64.png create mode 100644 platforms/android/assets/www/res/screen/windows-phone/screen-portrait.jpg create mode 100644 platforms/android/assets/www/spec.html create mode 100644 platforms/android/assets/www/spec/helper.js create mode 100644 platforms/android/assets/www/spec/index.js create mode 100644 platforms/android/assets/www/spec/lib/jasmine-1.2.0/MIT.LICENSE create mode 100644 platforms/android/assets/www/spec/lib/jasmine-1.2.0/jasmine-html.js create mode 100644 platforms/android/assets/www/spec/lib/jasmine-1.2.0/jasmine.css create mode 100644 platforms/android/assets/www/spec/lib/jasmine-1.2.0/jasmine.js create mode 100644 platforms/android/build.gradle create mode 100755 platforms/android/cordova/android_sdk_version create mode 100755 platforms/android/cordova/build create mode 100644 platforms/android/cordova/build.bat create mode 100755 platforms/android/cordova/check_reqs create mode 100755 platforms/android/cordova/clean create mode 100644 platforms/android/cordova/clean.bat create mode 100644 platforms/android/cordova/defaults.xml create mode 100755 platforms/android/cordova/lib/android_sdk_version.js create mode 100644 platforms/android/cordova/lib/appinfo.js create mode 100644 platforms/android/cordova/lib/build.js create mode 100644 platforms/android/cordova/lib/check_reqs.js create mode 100644 platforms/android/cordova/lib/device.js create mode 100644 platforms/android/cordova/lib/emulator.js create mode 100644 platforms/android/cordova/lib/exec.js create mode 100755 platforms/android/cordova/lib/install-device create mode 100644 platforms/android/cordova/lib/install-device.bat create mode 100755 platforms/android/cordova/lib/install-emulator create mode 100644 platforms/android/cordova/lib/install-emulator.bat create mode 100755 platforms/android/cordova/lib/list-devices create mode 100644 platforms/android/cordova/lib/list-devices.bat create mode 100755 platforms/android/cordova/lib/list-emulator-images create mode 100644 platforms/android/cordova/lib/list-emulator-images.bat create mode 100755 platforms/android/cordova/lib/list-started-emulators create mode 100644 platforms/android/cordova/lib/list-started-emulators.bat create mode 100644 platforms/android/cordova/lib/log.js create mode 100644 platforms/android/cordova/lib/run.js create mode 100644 platforms/android/cordova/lib/spawn.js create mode 100755 platforms/android/cordova/lib/start-emulator create mode 100644 platforms/android/cordova/lib/start-emulator.bat create mode 100755 platforms/android/cordova/log create mode 100644 platforms/android/cordova/log.bat create mode 100644 platforms/android/cordova/node_modules/q/CONTRIBUTING.md create mode 100644 platforms/android/cordova/node_modules/q/LICENSE create mode 100644 platforms/android/cordova/node_modules/q/README.md create mode 100644 platforms/android/cordova/node_modules/q/benchmark/compare-with-callbacks.js create mode 100644 platforms/android/cordova/node_modules/q/benchmark/scenarios.js create mode 100644 platforms/android/cordova/node_modules/q/package.json create mode 100644 platforms/android/cordova/node_modules/q/q.js create mode 100644 platforms/android/cordova/node_modules/q/queue.js create mode 100644 platforms/android/cordova/node_modules/shelljs/.documentup.json create mode 100644 platforms/android/cordova/node_modules/shelljs/.jshintrc create mode 100644 platforms/android/cordova/node_modules/shelljs/.npmignore create mode 100644 platforms/android/cordova/node_modules/shelljs/.travis.yml create mode 100644 platforms/android/cordova/node_modules/shelljs/LICENSE create mode 100644 platforms/android/cordova/node_modules/shelljs/README.md create mode 100755 platforms/android/cordova/node_modules/shelljs/bin/shjs create mode 100644 platforms/android/cordova/node_modules/shelljs/global.js create mode 100644 platforms/android/cordova/node_modules/shelljs/make.js create mode 100644 platforms/android/cordova/node_modules/shelljs/package.json create mode 100755 platforms/android/cordova/node_modules/shelljs/scripts/generate-docs.js create mode 100755 platforms/android/cordova/node_modules/shelljs/scripts/run-tests.js create mode 100644 platforms/android/cordova/node_modules/shelljs/shell.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/cat.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/cd.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/chmod.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/common.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/cp.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/dirs.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/echo.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/error.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/exec.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/find.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/grep.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/ls.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/mkdir.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/mv.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/popd.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/pushd.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/pwd.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/rm.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/sed.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/tempdir.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/test.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/to.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/toEnd.js create mode 100644 platforms/android/cordova/node_modules/shelljs/src/which.js create mode 100644 platforms/android/cordova/node_modules/which/LICENSE create mode 100644 platforms/android/cordova/node_modules/which/README.md create mode 100755 platforms/android/cordova/node_modules/which/bin/which create mode 100644 platforms/android/cordova/node_modules/which/package.json create mode 100644 platforms/android/cordova/node_modules/which/which.js create mode 100755 platforms/android/cordova/run create mode 100644 platforms/android/cordova/run.bat create mode 100755 platforms/android/cordova/version create mode 100644 platforms/android/cordova/version.bat create mode 100644 platforms/android/custom_rules.xml create mode 100644 platforms/android/platform_www/cordova.js create mode 100644 platforms/android/project.properties create mode 100644 platforms/android/res/drawable-hdpi/icon.png create mode 100644 platforms/android/res/drawable-land-hdpi/screen.png create mode 100644 platforms/android/res/drawable-land-ldpi/screen.png create mode 100644 platforms/android/res/drawable-land-mdpi/screen.png create mode 100644 platforms/android/res/drawable-land-xhdpi/screen.png create mode 100644 platforms/android/res/drawable-port-hdpi/screen.png create mode 100644 platforms/android/res/drawable-port-ldpi/screen.png create mode 100644 platforms/android/res/drawable-port-mdpi/screen.png create mode 100644 platforms/android/res/drawable-port-xhdpi/screen.png create mode 100644 platforms/android/res/drawable-xxhdpi/icon.png create mode 100644 platforms/android/res/drawable/icon.png create mode 100644 platforms/android/res/values/strings.xml create mode 100644 platforms/android/res/xml/config.xml create mode 100644 platforms/android/settings.gradle create mode 100644 platforms/android/src/com/cadoles/momo/CordovaApp.java create mode 100644 platforms/android/src/com/phonegap/helloworld/CordovaApp.java create mode 100644 plugins/android.json create mode 100644 www/css/animations.css create mode 100644 www/css/bootstrap-theme.min.css create mode 100644 www/css/bootstrap.min.css create mode 100644 www/css/font-awesome.min.css create mode 100644 www/css/index.css create mode 100644 www/fonts/FontAwesome.otf create mode 100644 www/fonts/fontawesome-webfont.eot create mode 100644 www/fonts/fontawesome-webfont.svg create mode 100644 www/fonts/fontawesome-webfont.ttf create mode 100644 www/fonts/fontawesome-webfont.woff create mode 100644 www/fonts/fontawesome-webfont.woff2 create mode 100644 www/fonts/glyphicons-halflings-regular.eot create mode 100644 www/fonts/glyphicons-halflings-regular.svg create mode 100644 www/fonts/glyphicons-halflings-regular.ttf create mode 100644 www/fonts/glyphicons-halflings-regular.woff create mode 100644 www/fonts/glyphicons-halflings-regular.woff2 create mode 100644 www/icon.png create mode 100644 www/img/logo.png create mode 100644 www/index.html create mode 100644 www/index.json create mode 100644 www/js/bootstrap.min.js create mode 100644 www/js/index.js create mode 100644 www/js/pagetransitions.js create mode 100644 www/res/.pgbomit create mode 100644 www/res/icon/android/icon-36-ldpi.png create mode 100644 www/res/icon/android/icon-48-mdpi.png create mode 100644 www/res/icon/android/icon-72-hdpi.png create mode 100644 www/res/icon/android/icon-96-xhdpi.png create mode 100644 www/res/icon/bada-wac/icon-48-type5.png create mode 100755 www/res/icon/bada-wac/icon-50-type3.png create mode 100644 www/res/icon/bada-wac/icon-80-type4.png create mode 100644 www/res/icon/bada/icon-128.png create mode 100644 www/res/icon/blackberry/icon-80.png create mode 100644 www/res/icon/ios/icon-57-2x.png create mode 100644 www/res/icon/ios/icon-57.png create mode 100644 www/res/icon/ios/icon-72-2x.png create mode 100644 www/res/icon/ios/icon-72.png create mode 100644 www/res/icon/tizen/icon-128.png create mode 100644 www/res/icon/webos/icon-64.png create mode 100644 www/res/icon/windows-phone/icon-173-tile.png create mode 100644 www/res/icon/windows-phone/icon-48.png create mode 100644 www/res/icon/windows-phone/icon-62-tile.png create mode 100644 www/res/screen/android/screen-hdpi-landscape.png create mode 100644 www/res/screen/android/screen-hdpi-portrait.png create mode 100644 www/res/screen/android/screen-ldpi-landscape.png create mode 100644 www/res/screen/android/screen-ldpi-portrait.png create mode 100644 www/res/screen/android/screen-mdpi-landscape.png create mode 100644 www/res/screen/android/screen-mdpi-portrait.png create mode 100644 www/res/screen/android/screen-xhdpi-landscape.png create mode 100644 www/res/screen/android/screen-xhdpi-portrait.png create mode 100644 www/res/screen/bada-wac/screen-type3.png create mode 100644 www/res/screen/bada-wac/screen-type4.png create mode 100755 www/res/screen/bada-wac/screen-type5.png create mode 100644 www/res/screen/bada/screen-portrait.png create mode 100644 www/res/screen/blackberry/screen-225.png create mode 100644 www/res/screen/ios/screen-ipad-landscape-2x.png create mode 100644 www/res/screen/ios/screen-ipad-landscape.png create mode 100644 www/res/screen/ios/screen-ipad-portrait-2x.png create mode 100644 www/res/screen/ios/screen-ipad-portrait.png create mode 100644 www/res/screen/ios/screen-iphone-landscape-2x.png create mode 100644 www/res/screen/ios/screen-iphone-landscape.png create mode 100644 www/res/screen/ios/screen-iphone-portrait-2x.png create mode 100644 www/res/screen/ios/screen-iphone-portrait-568h-2x.png create mode 100644 www/res/screen/ios/screen-iphone-portrait.png create mode 100644 www/res/screen/tizen/README.md create mode 100644 www/res/screen/webos/screen-64.png create mode 100644 www/res/screen/windows-phone/screen-portrait.jpg create mode 100644 www/spec.html create mode 100644 www/spec/helper.js create mode 100644 www/spec/index.js create mode 100644 www/spec/lib/jasmine-1.2.0/MIT.LICENSE create mode 100644 www/spec/lib/jasmine-1.2.0/jasmine-html.js create mode 100644 www/spec/lib/jasmine-1.2.0/jasmine.css create mode 100644 www/spec/lib/jasmine-1.2.0/jasmine.js diff --git a/.cordova/config.json b/.cordova/config.json new file mode 100644 index 0000000..610c152 --- /dev/null +++ b/.cordova/config.json @@ -0,0 +1,10 @@ +{ + "lib": { + "www": { + "id": "hello-world-template", + "version": "master", + "uri": "https://github.com/phonegap/phonegap-app-hello-world/archive/master.tar.gz", + "link": false + } + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..28771c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# Vim +.*.swp +.*.swo +.*.swn + diff --git a/config.xml b/config.xml new file mode 100644 index 0000000..b942cf4 --- /dev/null +++ b/config.xml @@ -0,0 +1,70 @@ + + + Momo + + Momo template that serves application from JSON manifest + + + Cadoles Team + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hooks/README.md b/hooks/README.md new file mode 100644 index 0000000..62e58b4 --- /dev/null +++ b/hooks/README.md @@ -0,0 +1,196 @@ + +# Cordova Hooks + +Cordova Hooks represent special scripts which could be added by application and plugin developers or even by your own build system to customize cordova commands. Hook scripts could be defined by adding them to the special predefined folder (`/hooks`) or via configuration files (`config.xml` and `plugin.xml`) and run serially in the following order: +* Application hooks from `/hooks`; +* Application hooks from `config.xml`; +* Plugin hooks from `plugins/.../plugin.xml`. + +__Remember__: Make your scripts executable. + +__Note__: `.cordova/hooks` directory is also supported for backward compatibility, but we don't recommend using it as it is deprecated. + +## Supported hook types +The following hook types are supported: + + after_build/ + after_compile/ + after_docs/ + after_emulate/ + after_platform_add/ + after_platform_rm/ + after_platform_ls/ + after_plugin_add/ + after_plugin_ls/ + after_plugin_rm/ + after_plugin_search/ + after_plugin_install/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being installed + after_prepare/ + after_run/ + after_serve/ + before_build/ + before_compile/ + before_docs/ + before_emulate/ + before_platform_add/ + before_platform_rm/ + before_platform_ls/ + before_plugin_add/ + before_plugin_ls/ + before_plugin_rm/ + before_plugin_search/ + before_plugin_install/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being installed + before_plugin_uninstall/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being uninstalled + before_prepare/ + before_run/ + before_serve/ + pre_package/ <-- Windows 8 and Windows Phone only. + +## Ways to define hooks +### Via '/hooks' directory +To execute custom action when corresponding hook type is fired, use hook type as a name for a subfolder inside 'hooks' directory and place you script file here, for example: + + # script file will be automatically executed after each build + hooks/after_build/after_build_custom_action.js + + +### Config.xml + +Hooks can be defined in project's `config.xml` using `` elements, for example: + + + + + + + + + + ... + + + + + + + ... + + +### Plugin hooks (plugin.xml) + +As a plugin developer you can define hook scripts using `` elements in a `plugin.xml` like that: + + + + + + + + ... + + +`before_plugin_install`, `after_plugin_install`, `before_plugin_uninstall` plugin hooks will be fired exclusively for the plugin being installed/uninstalled. + +## Script Interface + +### Javascript + +If you are writing hooks in Javascript you should use the following module definition: +```javascript +module.exports = function(context) { + ... +} +``` + +You can make your scipts async using Q: +```javascript +module.exports = function(context) { + var Q = context.requireCordovaModule('q'); + var deferral = new Q.defer(); + + setTimeout(function(){ + console.log('hook.js>> end'); + deferral.resolve(); + }, 1000); + + return deferral.promise; +} +``` + +`context` object contains hook type, executed script full path, hook options, command-line arguments passed to Cordova and top-level "cordova" object: +```json +{ + "hook": "before_plugin_install", + "scriptLocation": "c:\\script\\full\\path\\appBeforePluginInstall.js", + "cmdLine": "The\\exact\\command\\cordova\\run\\with arguments", + "opts": { + "projectRoot":"C:\\path\\to\\the\\project", + "cordova": { + "platforms": ["wp8"], + "plugins": ["com.plugin.withhooks"], + "version": "0.21.7-dev" + }, + "plugin": { + "id": "com.plugin.withhooks", + "pluginInfo": { + ... + }, + "platform": "wp8", + "dir": "C:\\path\\to\\the\\project\\plugins\\com.plugin.withhooks" + } + }, + "cordova": {...} +} + +``` +`context.opts.plugin` object will only be passed to plugin hooks scripts. + +You can also require additional Cordova modules in your script using `context.requireCordovaModule` in the following way: +```javascript +var Q = context.requireCordovaModule('q'); +``` + +__Note__: new module loader script interface is used for the `.js` files defined via `config.xml` or `plugin.xml` only. +For compatibility reasons hook files specified via `/hooks` folders are run via Node child_process spawn, see 'Non-javascript' section below. + +### Non-javascript + +Non-javascript scripts are run via Node child_process spawn from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables: + +* CORDOVA_VERSION - The version of the Cordova-CLI. +* CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios). +* CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer) +* CORDOVA_HOOK - Path to the hook that is being executed. +* CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate) + +If a script returns a non-zero exit code, then the parent cordova command will be aborted. + +## Writing hooks + +We highly recommend writing your hooks using Node.js so that they are +cross-platform. Some good examples are shown here: + +[http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/) + +Also, note that even if you are working on Windows, and in case your hook scripts aren't bat files (which is recommended, if you want your scripts to work in non-Windows operating systems) Cordova CLI will expect a shebang line as the first line for it to know the interpreter it needs to use to launch the script. The shebang line should match the following example: + + #!/usr/bin/env [name_of_interpreter_executable] diff --git a/platforms/android/.gitignore b/platforms/android/.gitignore new file mode 100644 index 0000000..a1c8ff7 --- /dev/null +++ b/platforms/android/.gitignore @@ -0,0 +1,14 @@ +# Non-project-specific build files: +build.xml +local.properties +/gradlew +/gradlew.bat +/gradle +# Ant builds +ant-built +ant-gen +# Eclipse builds +gen +out +# Gradle builds +/build diff --git a/platforms/android/.project b/platforms/android/.project new file mode 100644 index 0000000..46e7f20 --- /dev/null +++ b/platforms/android/.project @@ -0,0 +1,71 @@ + + + Hello World + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + + + config.xml + 1 + $%7BPARENT-2-PROJECT_LOC%7D/config.xml + + + www + 2 + $%7BPARENT-2-PROJECT_LOC%7D/www + + + merges + 2 + $%7BPARENT-2-PROJECT_LOC%7D/merges + + + + + 1390880034107 + + 30 + + org.eclipse.ui.ide.multiFilter + 1.0-projectRelativePath-matches-false-true-^(build.xml|ant-gen|ant-build|custom_rules.xml|CordovaLib|platform_www|cordova) + + + + 1390880034108 + + 30 + + org.eclipse.ui.ide.multiFilter + 1.0-projectRelativePath-matches-false-true-^(assets/www|res/xml/config.xml) + + + + + diff --git a/platforms/android/AndroidManifest.xml b/platforms/android/AndroidManifest.xml new file mode 100644 index 0000000..9b764e7 --- /dev/null +++ b/platforms/android/AndroidManifest.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/platforms/android/CordovaLib/.project b/platforms/android/CordovaLib/.project new file mode 100644 index 0000000..a6ec3ce --- /dev/null +++ b/platforms/android/CordovaLib/.project @@ -0,0 +1 @@ +CordovaApp-CordovaLib \ No newline at end of file diff --git a/platforms/android/CordovaLib/AndroidManifest.xml b/platforms/android/CordovaLib/AndroidManifest.xml new file mode 100755 index 0000000..6fbe1b4 --- /dev/null +++ b/platforms/android/CordovaLib/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + diff --git a/platforms/android/CordovaLib/ant-build/AndroidManifest.cordova.xml b/platforms/android/CordovaLib/ant-build/AndroidManifest.cordova.xml new file mode 100644 index 0000000..6fbe1b4 --- /dev/null +++ b/platforms/android/CordovaLib/ant-build/AndroidManifest.cordova.xml @@ -0,0 +1,23 @@ + + + + + diff --git a/platforms/android/CordovaLib/ant-build/AndroidManifest.xml.d b/platforms/android/CordovaLib/ant-build/AndroidManifest.xml.d new file mode 100644 index 0000000..586815b --- /dev/null +++ b/platforms/android/CordovaLib/ant-build/AndroidManifest.xml.d @@ -0,0 +1,2 @@ +/home/ghis/Workspace/momo/platforms/android/CordovaLib/ant-build/AndroidManifest.xml : \ +/home/ghis/Workspace/momo/platforms/android/CordovaLib/AndroidManifest.xml \ diff --git a/platforms/android/CordovaLib/ant-build/build.prop b/platforms/android/CordovaLib/ant-build/build.prop new file mode 100644 index 0000000..09fa73b --- /dev/null +++ b/platforms/android/CordovaLib/ant-build/build.prop @@ -0,0 +1,10 @@ +#Last build type +#Wed, 04 Feb 2015 10:26:33 +0100 + +build.last.target=debug + +build.last.is.instrumented=false + +build.last.is.packaging.debug=true + +build.last.is.signing.debug=true diff --git a/platforms/android/CordovaLib/ant-build/classes.jar b/platforms/android/CordovaLib/ant-build/classes.jar new file mode 100644 index 0000000000000000000000000000000000000000..a5b9bb509c44553989fca0f80a26384d0ccc7e38 GIT binary patch literal 342622 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 z%0A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

-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

SCoouu5#*ofS7gYB%?CAL;K3On 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

rd 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

hJ+X@DB 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Address.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Address.class new file mode 100644 index 0000000000000000000000000000000000000000..2f80db38fb46d23a235f0e1fee8377fd1fd7034b GIT binary patch literal 3356 zcmd5;Yf}?f7=D&qHpE3jKq!KWcL-{vt!))h(Q3t_P$N|AMV7FVg|Hhp8%5jtq4&!# za5|mow|;S^?Mwk%r?vgk&h$_8pLF`1vzrUaPV2`G!#VH!p7%NDy>I^f`=?(34B>tp zJ8?xtCWfnVG+|oBjEdLeh~i2N*Tg<6mg{19BaR5BV|X)$x0=y~x5aWpEOTPf#WF9J zY#a+P1a(uzqF{1ym{=0avUrh89?M&>f@Kw!f=I!!SMMrFOf2cQ^|WQU=_w%@R-l#~ z^MYM;6(qgGylyR~Gp=J=i~jMH?eJI`C%#zBXYA~<;hxvCuI=#3K8aeDck(oy$xLk0 z;2nt^@3-_7W5#gIo2KD3qJ#yt8br0|B{yeSu9?;Ol7jscS$id2yj9X2qf|)S%Q@FA zq$iihYSoB~yN+%Z3$(ddak%7~`SgTYba~#KF&8b}EjfmQeV)se{Mf>RV-$<@y>m16ZlR2ipIglu1=qB#q6%BVxBu7J1SVC) zE52yB)8*>#=pXQ6y1D*+9j^sK{R3=*cEU0ZeXz&J|7#}*Xnp<_G(zijn1=+Rn@U~5 zK|c9(J<&q&)ta_QmYuB@kb(mZ!obKWi19W#K3G|0OtmuEE(V)4&)V8nTN0D=OGefm z9=Ogzb#po=O2lS^v$JalkFUi?a(Xf66?BxPSjrO+&)6j=Yn(SlQEPsU9uXr=LmCAI zJLPzj8N6J|=cjDbat)_asO$}Y+Vzc&_F2>rxLeFX6*r#G8;g2=%vmh0aQf6>yQ)gw zcsx@w^9#a(t-MuKNZ-h4-_a9&8XOeG;%X>?x!bmBl$GD6JyufH4=>sr z0#YP$IBhLk_8m(UV2$f6eD=$xboyTiA&=^Xf?+KvI9!|WvO+^w`C(&Rdi%#4o345s zb8YVu1-pYhmC3dAe0rMWogWNyWu@eb2`47KXsd=HSubD>%32k@RAZ-KgpCqWyfxt~ zTer0mKEEwIL8ZC)L!gUaWk5wjO?5}t(3%=tLn76?hPKqv$12@DhKl9LEw)pnzeP=m@odE1nnBK1PoI z$ml4N67gx0l!#DBQX)oSNr@;$Bqib+m6V8>$`=8R(Gs@}GIA>42T=-b@S=H~^a)y_ zh*&bJ{EfpslKKIO??^OBx1v&bTAJxy7xB$hX#8jZxb0yb_(CA~Bu)i@ll3o81%gjw zECAeI555)%K7+FX;EsCmTp;*moMU9_1J+p&&IN$IsGsNCui!#}1+Dd$6ap?$#60uC zKhqLX5XHgY(DeW-gTJEd64Tdui2sl9%mZ8#$t0IpNB09pFTj-P8Fab|{z|>8ZMS0L?V*eLD032iJ$#j*r+IA2Sc1U>={c!9L^P Z=hE#?&kf(%5KkxBz{1%n-qD2D{sGb!A#eZy literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Connection.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Connection.class new file mode 100644 index 0000000000000000000000000000000000000000..7df0e4dece9d3be8aa7c351a88fd9de211a38bfc GIT binary patch literal 9543 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 E0FRC0NB{r; literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/ConnectionPool$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/ConnectionPool$1.class new file mode 100644 index 0000000000000000000000000000000000000000..57519362900a9ba2badc1aa4fc00b3efd7633fca GIT binary patch literal 2542 zcmb7GU2has7=F%ncZbf7&=#naFAJ%#Z7oYHYAvNu*P_LxfIy*qPj|=mlzkcNI8HF!fuAJRJB#DE$OC-4^DR>Po%BRX`vqZl%3bySgu5;%tA zY9POk6YBI`wLO`@DV$cru#Pi0t5ed5hI1OuYq%f~55}e6vR9xblXWLk{62hpp>Qdu4H5%<#j!Ac~zJ6f$6N3 zSGnP9xJa9qIsDk@1QUnYwI}76V+I9}5lqu5Qgn|BIg@R`$=a?jow1`A0?7@sXg8QRjx%&Fve(VGI>DwaLPon_0z z04#-1VCTy61Zt9DH75tvq?_5S<+F3_W$)-+T`#B#HG9ETD_6?)4Hca$bk?yiuQR|D z%e*)2s>&1CLM@iTEi22$YQV~gKw{kVk9*dXbPFszBA*jjlV2ie((kwB6or<}>s02g zveg}7u1kNQ*b%6H@`!?ud)B0@AlEKeisH>&PGDoQD#c4R5#E#jAe%r%m9GDx3LUma zmf941M!7JgrTI^7U84XB)PY`T|$`5aA!t+uFZ?XuF5V zXWT`26Nr-s7{(5cM!43o6EAYdw*z*QiwKd;MAS%%e}$Tn*gZruH3!;0hZq_9R!#R2 zD^2r=&qM2pHbob(Mqm~v)T&nC8|Xc;rr10ZvuJ24u^aPvZWhgoWvxJaQ)~h2A~@5& zfI5NLC#au8y}DCBi}Gdi?DYae9Shi?)NkZsV^MqBbRUg#i@%Gz^hyJM!6SO<5q=Hln$VjQi~?{LwHQGH z=g4&)NnAh|F7o5y5>DeXcUNGsC3+aeb!2gayPFupZH(g%yW%}e-~k)s_iTGVvg`fC zruQ@Q_>Fz4+klu6)}!y(S~+JiLs?byUo)g?J+rCB3~4LFh@GD zM`ekKm!e&ZzmURSMm>Q)`T5jE8(*d^&EzWL?&HlOnpze4Um^di_Pa`=^Na literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/ConnectionPool$2.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/ConnectionPool$2.class new file mode 100644 index 0000000000000000000000000000000000000000..ec2700b00b2f6983617950d176406c0f53c5543e GIT binary patch literal 650 zcma)3+e*Vg5Ix(*rp8EPy<2Zc(W+ond{cZ03PQc0()Vq;w5xHq=AwTg{)!JG_}~Zl zQQ{;Pyu8$fot-(%oS8ZM{_*+-U<(U_$YaWafoT&nCMqUo847VnM%7J*YTeg2ZgiXQ zP$XSfUw7iT>v~!#;m1;|Gp&PN%HNYp#`_E_wf_{XHW&;~w**6}E|oY*Zki&zLYDv0uewbm=EFpht);!K3!Q|%IFxC>(cjx_ zT=6?ja~&u@(2-Q_V-a_B%fy_Gd6aDwVA?36Oycy{rn=4Gq>OIBRogvnUXgCJ<2Q7k zDD}1YQhz#z$~~9yp(X(YS4r37L6FI$i3f}Hmj-Dx0OmO9p!CH#x(5|oFUUP*IYVR%lmk4#CTnNDg<&`pF^r(xV_45(!u}RM{wQR#`G%y>eeyA!hY>s|AEOGs=f!M1B!?f)!+ty>ACJnh16~}&V_tk8hh+B$ zUi=V`%hnT;;7o#=nZ!6ud3~ z0ktI*(xVMQEf&*b0#n=S&+Tbg)85|H(Al!4y`!gdO;1B>Q+<2aS^?1_a8g4!6f?At zv0e+t^(^jyOJI6qQ*(V+YiG~urlz$$^{p-In|d0%*44`;dfGb3xr&^zftaE9H|m?T zc+e0iZ}o@!YhoA1wWuDC)P%QeHjGFOmk;TFBM=U)4TpoZ0=|B2TT5?HPfbwGf-Slp zsSgIW>W%TJCaK#wn&(e4vscu5fwonvi5r1nO=}>uMel75#0;*O+Y#ssX+}J%3!IUW zsO|)+)h_2U6ZLJnKW>Dh9eQ+Yz|Y0zI2NNS{&+O1hm4x0bULz5btu{p)U{AN(x3%{ z+QuMPnUQ&w1OeF>9iO7knht8AzMA#nK(DE7PF)}rFqR8sSG25}w_d>A5bmY4iG)UP zkN0oXqn(y~Uu)Q}1=nlQfb83YZew#GBkpY+ozSNnY1`wgnCDQ@hJEQ#gX4m^7S;X*hL;*Tq8uSryV2K|>}xtZv%o*CWy^2$q-1C4FuVbr_%5rJ2+aj)&;66vhZB z;#5bZcOYf4J?%~HszB)p$^CwI?!`f~H#XL%LDZ5%zD<4JURYAaJrnLAjF-B^Aw*BQWi_YS7Cz5y9S+ z5i&Z{ylfzn@U&&ekT))8QKGtkz%Qd{R%T>UD%48H@%C#28}*LOOhE!3ondU$2MK%r z5lRrK#YYT{OCPW1_j4o47cN{VPFIgYgD+Qu~!3oeoi&K=)^%)JS=#s3Ez zUENdX587!XH<@vnk}W9A1k+(e1ED_RGbu@sNXZo25spXwdUHVTNI?pFY3Kr(omHHN z4iz841{EL0$5iNuFeWl3Zkn4K_NTII=jN!c^~x0!c~-%nRs02S2vlU`unvQjLApCt zKPRroW%^jNMaEfax{?asRPh%6DiwQM#mAxX+&XarDPJTR-chj;eidP9Q$b3V`e;-e zkf9`r{x-e^7c2O?ihtmr3jU?yQoNg3(cFY&%raa}Ip%0RkMyX_f=$tAII7}YbgTF` zwyO9K{;S|U74KtAWfj21rXSxZRR~Gy5?P9Ht0G%=a`3Jy6yZ@st}47DPZ6prP7)JT zF%e^m$XCTA;ZsF{d=w(0h{;r36scm0I9V0NVroL!47o=YCE^r;DJf$tKU*0O1bg); zXSzc2bSgE%rH0mLWv+^O%Su%-O-z@M8LB81WvZAdW~riF%qDnZjw1bjV*Vu8)a-!2FW#pD+ zQYaAOVHDDWHC?Qq=xn{3-X9KG!Pcz#c}fkida5`&6FBpiQ#CV8ZB7d9uV`sm(fChM7X;kZE)rX8b5GpA{3aVCGYd1bX{S3h+9V=R;?k7z}vrIP$PIzLW=)N`_P z8*RiTMoJ)NeuSijXovZkL*qhPC@jOwM3jfHkGjb(nGQpX8gfE@v*bh>S6fLlJCiEO zC|n!Vj7{Nazreg>7pKN6W)+Yw~`{6{-k4Be(4~PHInKNhGY6U@qlgw z=?6tNRUll`ASYxRHe(}4i$wHLufTjKT6TS4`--Dvuv0m8NTW}nYpIfv-eZKVRga8? zWG&(jhWj=gv26)OXpx6?YjYqPqpxS&S&}TbZ7@T}k(-iVVNU0F%qL?w&vCMF>sgK; zvH7g=S*U6}%O<1;3xkB)wl*4$@bo6&bH)WHakSPkA!`kX`nb6fEgI9UcAB9HEa;Sz zOyMTeN}fFY#^R2fe93M`R(ijKwS}iepFEd6CM&x~K%0=*f-+t~tl_nR2UD>Q9lV0* zl$QwTVt+k0B>OGwvtr?#PZo*hn{}f3W~oTJ^G&`U&a*Bv$60PA$9pl6ZJwii_Hp(W zc;V)|t#TjSm7~b+-iMsM$YN9J&T<#Rb055;$m6i;J82jb_F>{)Deufm=Idg@nf@+E@u~o1T43UR5s*O{GJW`Qzipn2Fu{3__2ufVM z^kPZ2VGwHTD5evp8T*zaiY_%yD^DUwCNJxfIb{E^0?H2V74tqVe zq%vHTRw{7G0XYpN17r2C!lx6GTBJC&4tuMnTKY&KNj;Ya|lyeuQ z-%X9~p_F?+fJT?%G7DpI2`$N?-Xo$-Vq_ydgt_hWM^GW5x{Qr^CREGZ#qJ?g4xy@Q z2-Q2s4$JQRony}oV}Wee=wx?Ybv<$h#~vdWzhC9>oLx9|7>i_c@eq~_V(zl+V)w8) zIEvHgW~ckk7{Z5&vxl&32(?3~8ywqS>~0%GR`ntHs?80`ld7?KCg1t|7mQ%J3md9; z(~$ECK@dy16*4f^p^#5%g1x*J9-@=(<2C9qBXE?F`w*k{VRAe|oWQn{j>@3asm~?Ogi_c7y`5TmfP>9j4SYITy944h`s#; zlwm0y&_(_$Naw<5sg(>)i~e(@7x+BBz^BXwW9&<34G>%Uqk9kE^LN2hMWFT&K6Z)T zib2e5V=sZ*S;UQ?*sz(jmECOzBvxcNlmGhagM;w2S09|eKOMO}6j;clRz~0&30fD0 zcQGH!w-sg0R26uZY4174^z%%5hf#nR$n_HWUMJ_vgyR*|^0s*eUc*`ZByYqUOond~ z=(m{q-sXn9V}d6W<4kf%@MN3>l0XGa7-gh?F$u<1q>*4OO;?%b(3vb~cB0s6Y0Any zON86hRc0~DPHMO`so|HB zIrMRRyBeetjp&!D^ls;7>Xb?zdoD5Yf}HR|Yvf9Z zd=HcPS8Xq>;ajHMY-xtf&dz*$x+%;$U$Pl0Jh{pIb)Es13)hf3!R)$wT+BOoh$NU( zl0_;DTbVwCWbWnF$=!H@0Vz+V^L>rOXj<)S=CjrJVLscc4#CT~IC~H|g=kq>d5C^9 zjMcl~8%1k(R@pwZ-H*~i%x0>YEQhLx(ViTgC`UYYH&qH$GUo#_A*^6XpT)Ddo<7&W z?BB?ZXyRxy&cWHNVOAwKD2K=YHMo|1D(9|ai$x<=GfJ){Ze^%53xq7Tcbd@cB9%Pl NU33lWC!>+S{{ecUF)IK7 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Dispatcher$RealResponseBody.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Dispatcher$RealResponseBody.class new file mode 100644 index 0000000000000000000000000000000000000000..d7030e55ecca179acd810361ef27f8da19be4931 GIT binary patch literal 1457 zcmbW0TTj$b5Xb+g+oek>EG{=iKv2}ZAa%hz#t5rKV37m}iM}0nPj;(ITidRYPvnax znur=7eDuK&Wt`LQ1*Fl$hn~xH<~K9{X@CCu_8mYGOFB}x)C&!>a=EPI3a;wNA}3FI z4Radi8PcBcUB~vt6Tz#(^BES)73aY8Up2WWny%@*tOtQ>T6Q2jn>WnxwtX^ai9xY! zhLQ3M{+gSXW3Jh5GuR0{!4K$V&wb0bf(Hy6+5dpYLUVfzYRRbzYN2e|;%W0>UwFHG zzd@Ev*{Sfx9``JHZyD8~Zc%%K+k!XR^{+V9Lk45bwuM(}aNif?QH-tek>$HQsMLiw z`zL`qOj4&3mB{9vGw6@sRD>H?q^pMO41E=cw4+Y>KMIr3>*gQPT}> z*G!VpvTJ1QZ(+*9t_Afl**YcLKMX`9HNzOO<7c4nI8Co2RxK$|y4%gXbT`nCqJduM z2Kr!VSTL}N8yapJxP{vW?qEv8T?RAm+vvhhNu%K&H5?bz9>Huh12x))I>m2wGz=T1 zaTnt-fBh~Q25KTG9T$JNEzn76C*#O~obb3dt}L z=g<}n)AUQH=s#DGkyE2nMh=elBt88Y01cT=&&VS|dpiFGEMGW+lAk+5;v<<94APo` zO6x;fmkG2&fhC+F%XAb*??>oHfG`aUPco502}UtSyG%1jH~CIc-^n#3_k@xh}t7L4_uFyV`{{-bT)N{I#@k)TBq(eLiA`9)Iz7I z_i;=RieVB{E%XBU$nsJVy61g|78SX5tjJW0#BhN`h}ttl9%)PQiEb%T@XoQ|?a7U0Q_{tB5tqqCutDbx5vcAk4&>2^G88{ha=U z{(^qCN99n?>FK9>PJcr`^@p^5?j#`rhPH6dWZw6_%k!>tfB);}UjV#@?_%i1O%3Bw zlIkzrf(cA&n2MnZH)9ClRttJ?TSGR67;Y+JTEm?f+Hg09dzfj(JDAmQU&FgGbm2Wk zzu$^o_&{lYsK}2LX|!SvIrYe^1F0-fc^4jNnAcFyUI z70Kxuw{u4Ep5d5^t}-KD!6f9qKp$64w`6#^f^_Ics|KlIQJ^_1bJARvj)0j6)SX(q zPMD)blUW-Ml*mdZ&E4^^QmvykN5d+%rkrn2;7FjwO+Ja(sdy0R4iv8eV1qc-=BRlS zII)AuR#;5?f;}e?50qC`5{Oa4y=Joz^Ypc)ygc8xxiTxIT6G4u$o^X^sO%V4P8J3B zCbl<~N?*u4DzK-)X2z3_!LBEUu&2OvZC7MRDfq1U1NNC)ka>Ya!8KRWDnGGlyX@rT zHB+@+N4<+qsgcsrj{)ZQe~y=iqK+k40*OEkw)vvWUn$zTMbnzUt;SG!uywo&M!UbR zRFS-HxCIWSj$=5^;~hpznJ8&^sN*Ue4XzFkWr6laYpy4-yUw`mIL3;aSEakG<6}J1 zv4Y1sKEbCtK0{f@=Xj#w3msqLD;;0MQS5Kj)#=LQ8>ajI0Kyyjn<-Xx~O^=OEOs*{m)S?y_3U{+F|1!F1K5u5sz5V7Qa=5d-1Ji(Vs^Pwe250*8VVUa1XE^B&R5 z`$mXY297`9y40M5>&E9M5aBQP4>^N;o8#p}@HaWI3Nf&b&}?UOXY(F}e?oK}O|z@e zR?++%Ej){nYJCpGdD(Te z%?=DEPp+bUC^GO2dh!K2*3cQkuh=ydjYnUidmUY~(N*joiq-_;(KYM|VBk81U8lrtVpJ$cDoCm*i3#U$-bbFr z>v)4XRJ;qgNV{zq!w`o3NY66LHxZ?NCDL9-m&PS>4&yCcu15Nd`s((VR@evEu-}ht zBKZ=Lr^z+E!h6ukHN*vez(Kwo5DdJ{PlX@P!I>Zb{<9v_0UzsWwDWSg8)u05ERmff zqVs+%=jiJcYgxf~fJm-jl(^}CBfd0O`54i)lXHy`gf=3ma4wP4hqsxdN^dNaRu+2v z2wvb&tvnOS-_V+5Ox-L%9b>yMeSufci|8g2mE*pOg$)cnK0-m6wk;Sc9EBl-3^hZz V!AhzgQ>c0vQ8Qy-z?r6&e*i=9{ow!r literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Failure$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Failure$1.class new file mode 100644 index 0000000000000000000000000000000000000000..6d547df6bfd66217d141aaaa836b343f4fb32742 GIT binary patch literal 212 zcmaKmO$x#=5QSf~TCD}U7r}*VL(d=9w)Rp+l+=Uk_421|?kL)cJoG7*Y`j)8x^W{)*9OS=5feJllK zpx_7aLy7mLDb+O#CGhThdH0-m&b@j0{pZIo09|ZUQNaT>tQyeqP{*2q5}G>Jbvz>I zp*&4w6cZXfCpfXA(?oO~s!a~pW<(uTBFT;J6NT~M$M|cM!bk#b0S&9d4#EM=d zu6HOyg8AC_Ww`5!D3ZLfo-1%qxLy*97je`v(xEZD*mFpe9o~&f_BDSW8$tNW;=QPohHujtnofbLPzeos(ogL+ElqF z3|uiWkE#h1R|(4n=ctr6VXYu#+(|-hBIRxWSURx|ivYr_*}N1Q?ry6uv{59ai&efi zI^QFWA2yiI*e%Bj%V4)WUgMR`k(Hrron!86nzoQ70d3THZjKVLh#R~jrd#4sfuE=J zfNpJkhh}}@R~i)D;0SD@%>0VtX1dlh3I?Q_)X4_#<&e=7*%Kz)x`a#_Q)IVrJ0siT zKZUYo{6y)4Mdv6_#Hj)RPyg{|jD*$ZaR+xZhDl+*LAwb4zc9I>wvK%y$* zfe+xL5VN+^ATVuSc4v0yoS8Fw`T6Vn4*(XP>d>&Eql}gg1Dh3cx1{w*T5Sy-4P6aA z1~3>eJx>ICE)PQyYIw|`J&zstSOjDR;w%=bapd?OLw#_;6qicg0kIFxJ*wSjMQ_lO6M^s~icG;+fK6`RphA=+>%aC5Fg7}naI+{jr2 zmMJ1%_KW${=JHQlVkON`CVd8FVo^QUL^J4b{W!42fg_t`WIWrlLIX7{%HfHDZI}jb zVZlHjmVqj6Gpy#FbVk5Xor!!sJQ23M8&?2YRP4r8`i&G4 zyY6VFoR;L=otJZ_b9RT(r1w*%H>ObgsBL7`WYcIaCTolIpze_Ojy#3tdiMfKxAzT& za}?!VI*0m&HWbuptPu>jPh*2#=L3SSVTo3jQZSaWLLSlJF76REqok`@3N!J6Quiy0 zpD8G%RB0JlPiTz9E@d=yc9bfu?@zG$H+bt`a8=gY$iVxQsz6E9ZtntYrY23jlAxPu l#H9k2)JX+|B8^RAQ1CD*dL1`tu8}W4CsfPS2@N+<`3=&)9jgEU literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$1.class new file mode 100644 index 0000000000000000000000000000000000000000..55f632a56d2b82aedeb4ef0b1a24d515a17058b6 GIT binary patch literal 2433 zcmb7GU2hvj6g^{`I9_i)XhkScpiq}4PFp7}w17iOF=_4MBvL|)!~@c1JxaE5cHRA` z=p*k)Jn#SyAb|w$AVC}Pzz^U@AZ6GV9GzRyvmBe#kT1j)x3v+;mV*_a}E!D zzgKH=*pXh(u|3%^%mZ1c%bI0d{<=VQaYCP^`vQfA(~$ymZOfKh!O@;{KQ;Ec+&R^D zOrv|>a4oftHw%iE00i`wZA-V&H9SvpXKAvKl~oeW?@M2xwb*`OJThvw^lSHaTJ>nv zHSGP`uJ2m*e!LU-R=2ik^y*6k`%rRUzd{ULOJH_jpa2DCT=_7Np1&#m1E-@Tg%Q&+ z=oK3^rO}ZtrOZWENnC-2;Z!{C_0w@@*mP|iKV{IiJU_!?y}nMW+Qyfr?D-Z8TEvDx zY1i7f4L@*MiLah9QyD=fqj6G(djV^9Gm}YF!FI!8N0>@NMybL&D4k|vC2%I9HSRA^ zJ~AHf$sKv*JYojU$8pn@OZ&F!s+FgLUdQlhej`P5xK##D>IB`}86r)H)1=q2lm??4 zdNwV}PVpRu6F7SkB0YWAFb|oTanSst;ye=?^jn$7J^SqT4R)QtHD#pM3+Dor%%eBr z!OTa#w=H$J7sf7-E9z*l`8RB{>v%kV(V;2gwhkRLI%ct|<3*g&aRG1XxPzvS7Vhf! z1amst*d+OhuByta!2IAKZtp!{*RaM}&fAB59bw{GpwQ8BYOU?$#0Xr-@*R`N92ll4 zJ>IJ;yjkyNr+Uooe{ZJ#&9(IT0C`m*fAMU{3TL>lPHHOEHGLgdRkZ%%np$j496Bpy z{bVO?hI4#%X}s>s5cBh@5%@+c@;8e)?#^@eHgfy|T6OtPi0V`1e&;HO=Q&Q%2KXAM zIO^eC!)YvVB~&XRA0kK;_yx+Je@s;G>wGFE(<)KND2_(>iT&|&7$K_obW-uF zxE5pFBDzvs3X^?|=~0khFpXbBkcG%FNkxeb_YPt5xK4l^Zs1)$3;g>8yuhDo))Jrm F{0HT3Tj~G+ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$2.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$2.class new file mode 100644 index 0000000000000000000000000000000000000000..64cd3be0f370a13ba742339d340e1da391f08acf GIT binary patch literal 1046 zcmbVLT~8B16g{*3*wU_0K??Yd7HJD{vGJ`26D!8XRTFD?AGQ-avYlD?1M$_U|Hnin z@xdS9k22mVR7tw>;KS~ob7$tC&}20V^M%y8H9^~jCiq&yO7=<5Apl7y~QiHH;r+=nvW z_oB4R{h_E&L^=$`ds4|{o55>%ulWIYrFMHNOp|^R2|nulk7{$5A>Y*l!7%4ZC7z|D zJrTX+djUn}J?-;gmq*g@lVCm>N~!@2&CG<4sg@Ta4z-HKaS3hmZXIqhEN0qfDENVn zDPOK(?38y7eGw*-1Z>^=WeCc|2m)RZS0h!Srf z=)t>FRv4Z%GUsr%lTPy=vsli)TV^oLESH&Sutk4Lk$xIht(yK5vgmPej;_rtq5H&h z^sTfuzk;B4G=caCscNf~zPKnx|L^bc!ZS-ZlG312{+4xW)!`pV^)#d z%G}X$SI0cVirIY^q@KUYho&bF&E##yW04I_dElq%(A*NqP)3R9$}IK-LvE+VP_7UOPZ+>pw4zAFPRNr)Bn;K_ z7M=dS@KT1w3&}Ce|1EF)%j4k}k9e4=MpnJCa(BV!&ZnQ1}>AoLhJ+bgn;MYz>a@Z zz99EmJ^8QDw9ZFp8zWjIS~#aV(c*}HqVh7X(Y6*)!vdDbTX>A8bjTu3v5A95O>mSwe+$Dh1>^K>AX3xF%oU_04yXXFP_uv2i{0qPU?zUq; zhNSscnsX`+;Cwrh7*^SgNOM8OMHFOUR7Dpq$-K)duHdSIF$LEM>WWcKc@@)5qu@FrJ`v0bTG6tEGhQ`Z zSGa`1P(;)6gku@i+;!7^QgZwNHMIr7;PHUZfPx7^XAqke%f4{EVy#{!jD%t~u}uB{ zNr^maTBdiI@JD*DAf+FS6(eWbxf$Q9``(=A2%}bL4J|zFv)#ztBgDq-MM3B&nU=We z*A|3x$5^Pcr>kU_jp{waG3C19jLGg1K)Bc%tENV!2Dnv`r!0t`@ZA#H%2nHC2GO)6 zs7^dBi@ImBLKIAL^hd|^II5%{UMm)5Mts3vS`rS!K4j6w?WHAGcmyi)qAIM%UWHNS zY~Lx1NmFjEr|CS;%EogSCM;Rov>s0juVOE1=)-p!deEz(1DzTU;;{5hX(-C&4ScVm zglPpgHO%0ah7?X}xGl{rPAHhukVb}O)spr@nnmc_)&z5BWq+y+1$PMfFzC-6JK=oT zBTYSNVnaBz&80ZAb1H;KE$V%b3hhmY3ne)E?XQb!l*__(Q^R>yR-r{gO*<@P9D`(m`4NKNV$DKEDx53SOqP4p_StrCpU|f|A!NdMgo*^m`7?fi z{{hj?PN{i-N0xms@{1rNeD~o9e*}*5>;@ue^{=fAPXy-t59qKB>s9Yk?U`d<_#yp0Caf{k1v@^AzpwiFi zrsqh~3mm7H$kHpEqu01VZ*Y~~2GljV4U9FYpW=CpJ*WBR7rjA!o_#TnB$z=Wd-T{k zwB0_aoCNxXi~Sk^>RYKhy+}YuHYk!nKhu?+O5iNdqS!4LMUMRu-o!vaA&EhB^Q@1v Ux-gDId}c}hKYzii{p{!KBb;g$LjV8( literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$CacheRequestImpl.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$CacheRequestImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..58db9fa6ce19949578ea00666416c172f12a7e0e GIT binary patch literal 2150 zcmbVNU2hvj6g}5*vWdGiA8p-~LP@Dh>`llf0n#K+3$2?{gWJ#+iW>2!|A15wPytmD;(2L5s=BIf z*Hsu5*J@RPS@b*=6sk@bs!#wykE*zl9~ij6crlIz)1|V%W{0=yPN3>F+rPCMMK#;? zA{BT})jscrw@N`hhR-zje00*P|g~2k`>=m0$FCb z;#WRk&1lsPGn0bRjx{f`@KqJod@odSJ%aQsxSkuG5xkS#<(`gdJGPU%PKE`)LbClO z*Hf44Ybz>v(^;u&Nlf|PPweYFmq~>g6DUsUOUws zk1uhD5RdVu1q*w|TW$hQ5%8K{56bF-t7T5NsWzc)W#R~)H1QOkHgOE2CJrEN;#FKU zaTvoqfll6SgKFz4Go|5*CXQm*z-uO6N6Ek?6PK}M;yH{84*cutEz%2S_EwKa8N+!h zvbUPSz#D?ePMA9xmNxa&`&*A&a3ov&Unl&q=fmpkt=+jk-!W~czVh1rCp)RpcA}5% zI5#;fuy)yDK35bR?^L11>#fMucW1fkhw4h*RZ*1}S328LqM#S_RS>hy?TEGY?!+W7 z@P6L--5Am?W|Yt#jz^k29%)BlU_kpl&J?=z8Rm`f&Evm77e~t)Yan55pvxL>AZd*! ze?fNxJ=Sk9ZdlgO=ouT|KyL$m>&#BzIG<@&g?xlQ`561<6C9RLk(1BxY`m7xs5pTP zM;&Q)37lk{g-O=O7kw2!sCsL_#8x literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$Entry.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache$Entry.class new file mode 100644 index 0000000000000000000000000000000000000000..f748fc43e717269ecd264a0a4d96c1e6ba6c434b GIT binary patch literal 8443 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 NZgkRRoWMJ1{U5_!RHgs` literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/HttpResponseCache.class new file mode 100644 index 0000000000000000000000000000000000000000..ccd4220bef796090439711ce721b2b12ae013e7c GIT binary patch literal 9921 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 IKZ7OT0ks$XZU6uP literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Job.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Job.class new file mode 100644 index 0000000000000000000000000000000000000000..f414b6832a8d461f378d3082f824630a1d8036d6 GIT binary patch literal 8622 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

e!`9Om$eB(9>X%eoptehFTZ=( z4>0;PW?IN_EgJCicngJCh86e){31sb!dF#DU)D&S(JD`pk9w|sfzLSy+sXHJhddeT zy28=$i|C9pY8G|XMr*HN&NLQ}G)1Sdp{A#wo1ns+&gJh;G$fJB78nk_Q#KF3J$?=*WXJ8@i14^-*IA zon4V=lg#6dLHg_P>r7)2HAT@(FB9VZG+h{<&9_nb?mdExBSTc>9RNpnO_VU=Vew|F==1Uz-U4`}T*RSuqG>u(!>|0(S zc~7M)$S%lm1D^^P;9+{$N13%B!A>e@2#>kyX!qDDhUUG#APw}=-@u1RX#v&!VN$6n z6DdTB4|^ho>ZqOu`lq_Wt%vBBn_onuc6sd1W6$F-RhB&Vc7+MCZ+mTX?Gt26-CX&T z4)*V1zuxaR_=9mB`=EvGsq9P`#6rsR z6rJs9tmd!ZZFIvVo~5HdN9TT?PW=Kc^%?%M|1#Up%EXeN%-^;s*(8n=$9!D{}V{#y*fFxn*S2TRG}L;4_1Osz5ANIXr;x6&gh z{!yAlJJ*prbnY44rE}~a!cq@tiwCsD1v0`k(Cd!h?-Ua#Nf%h==;Mq`^{iX*Bu63s z|2zB&;dc>dzn5ai_)h{x>*|>)F5_L{dj9)`PvX}&-$+G&n#yS7I(ym2Ue|wwAIiw? KsMHXi^FIc9+;mO= literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/MediaType.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/MediaType.class new file mode 100644 index 0000000000000000000000000000000000000000..30a704d560b0b46a528befca3968a0982b7cecaf GIT binary patch literal 3176 zcmbVOS##4?6#i}^S&k8#!={u3NLakYF?&k_q#*P!02=}<}>rcAd7^3WgE_FTz!Oze`GW+r#hJ?A^;erLJ<>+fHF1F#EU`>+KA zbx<(Khf{nQ;=?c>Mtm5>m=CA%HXp|8a0X|6IEVB6bb^1oz_%CqO7)_RZzd(gB~1BH zj{z?HR6VD8k!A3l8XXwvIqHSYAdid>_FNbqJ;G-O#f8Y(DLraw z3GI4xP_=E%G6<<|uxqHRuV0L?MzZOH(6N4ld6@~2;FlqWu)xG z3?~DXzWu*1!7;MfZBCKlm9dne_2<%)nl++M>h#4QGvlg0rdlb!FMJg2WQuORDHb== z(d?C+YH7Jl)V!Ru?M$?Uen zB)Ctt<4Mip1e1NjAi5dW1cH_PFl;P-Hd1D^Ky$R)rJE4;7d)?aTEMGzL}@UkO{+QG zO%jF%*LHPTuWh>7MVHiwPMvPNww$to$xB+??g*YCCd`-9vT(%UO{&?X8^+o|kofW* zjO&GDp$`;f->{jp;@Ytk5A2FkoZ5Jf%ZMT-Ba9Xqt$c{^p^Xm#1SRBTT*WmB*Ja$m zO&PavTf!X~ckzyddotd|don@@%6K0qWPHGf4{=|{NBEebd7+GYbzMuSdY6^Rr8UFu zxgOUtcFHsu)-MRTY#hm@^eG;?`aU8umC?1$g#cySH_P}0pUOCjPVV|=42`c$MlQ5d z!sjx+z?U+5a7;!oPB3%^&Z?1{U6C_8BL^Z|TDET6z9STFo49cC*6llY&xeE2CC+7h zg$E3$I?iQ7ONbr{bha-ca=STjcB1)wDA*iiShYZi8)YiFCG;ufO9(|qD_akPly+-m zQEBqLAEpe{jJVcONbfTBg~D=URe41Ab{J))vfYYv%OF^-ydX$r6Kvy6-414a+HLhm==MFX1A0*0-$tHCzfZ!g>L zpgnaFI&0uPf@VMOG|o)T#+j+#I5V{zntg;q1xtv#Xm^ixBFznpgU}y;x1;G}4uWc!Ov=K)ZJ8v>h14LHZ4L7?bFPjW_WPy6_{NJ;O1F+#%AQ zM2xgrAd&nX(rtGF@`83euwML17>9_;Mtsj-8nPb5xBR&w!dvl>zd1zsK0F{hhbUN# zzIM9QQ%cYSNGM|HDQXv7_c$N>9T#L*pb%e1z}1w6#mZwfEJ8E?TkUUphD|@iM!fhl(!g^wP2TE^Bby0RHv`| zJ`dMCtKH^wWp3C((`>)(SRwDU%wXS%qL#V2|F{!5+>cz_ih^+Fq@ToV4Ib4~cSEIe zzf6WKmAp(Xa)S1VXt>+r=FT3sqgwej0}Dnqjo}9iMbuZfC1Hr7K|sJV#Rt$(Bd`?= zQ)Vh@!wAOdL;x`ji+6%ZB7#epNNG%3#oa*VGo+8SNx+2`;86^yCj}`W!{sxZ<=*C} zXExI-5}Yt-6O}}(S^WX!0Ojg;D5OE?IKsdI#*&0g2{}%v%6lmChaQdVG0jKuyr&jma literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkAuthenticator$Credential.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkAuthenticator$Credential.class new file mode 100644 index 0000000000000000000000000000000000000000..9e842a50ba77bc7b904f9b11e25f558df8f05812 GIT binary patch literal 1748 zcmb7EU31$+6g}(6mLrR%xM`Xc2!*D_A9dW8w4_N1wL?M^@=+SdObI;5_7baABq7UC zeoB7K#jJYY%3{vIJZ>BK5DPl)WKlDiT-ULv<6{FODt{hJ>ancj6M+kBi#^+M?HD@yMF(%8l+`Lk6E) z4JU&0nwGO|1-6QlO)YHO9RXu8kS*zkw&e(zE3PYpMaSxNB+ss{HNCxR=i9Co$gW@Y z9<{^JuWml7b;GtQX?54o>0FDD#zxoAdx*Zv~)}E}nt$XD8y%)69 zwLgT4acZY7pi8$&CAclv{N?ys+pB)zcDlar1)*#$sSL`x^tdVg(DqzX&nn~%B6H~< zA)nfn;oV+uMhnH0jnExQnH*Ah$(_x{L)i@Hi(it9_p-0a5ie_7opx;9P@%ZOjnIot zr#o9-H)zUbTiH0;r~I@U5))&%Yhn~<1dMw;Wp?() zt;#hWpPE?1x{eJKo4BXrGlA(>vz^V?mFpK2mvaJB5sm*5Twwf|ZH@C5C>xf7z$4u< zu9&Fes=(>vq*yQkio{{hSiUb^dR!SWX(t^@l%UN$h%Z#m(&KtOKx2c@)KFa1f@ zY8ag=`j&cW8B3RP{DT2FG0Iu4GDsZ$%F|l&N{$rPuCAILWI+Q5*fII8ac(> z&a)4o!5*5txrIxRJpBfB>_$8ncs`CI-eJ!vX1vSKMfP(EZ(@pj8Z)zuE=T>W;=M>4 zaz=qGPB?2zNk7#n2GXTpkb25%V+t8=15R|E8LiWaEJBT4QhcA;O5n-zGvuCNy!;n( zgi%oYc>M`G6GJp1*#sl;Ze1HF)E2v4gFnN+wFgw};VKJPB^3=U2|op2H=+xsJY2>Xqh^N_=<}#rAkgK7LNa$Ti{;cSYsk$mxf!UT5k7S!|MEBa(|qcSZNszw_^q!dlx0FY z3~cIRd8ss+Zv9xdGf$9VKSweQwJdHe%#io*#xnK{og9NJkun_T8d#*j(9ATI<-Pv* zTa*|W3iOkJLXlwuWkMA~MLOR^b$*U5Vzz&0h~3G0YFMY*AiPGCMYK_(8le3NJ%h`c literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkHttpClient$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkHttpClient$1.class new file mode 100644 index 0000000000000000000000000000000000000000..11638e9bf98965ed1de7501419d7fe288a240402 GIT binary patch literal 1394 zcmah}TTc^F5dO}#v~*c}QwVqiu}WJiOT7UWNKC~*QiX_;;M-D;u(0f@+bw~AV0`dF zeepl=pou^tiN5=zjB~ad+OCOh(lckKGvCaaZ>GQh{P+o=i1`@$kd;SHg@(L}+ZdNe zp%-^lOhE6&WE4deG32AT8^t{aZQrmmHAlFjDlCR{Wyjbzbjz@}^i|g}?X40+#N9UQ znMsDxN>%LX^|uYf;fn5i!AAis2bLq;h0kQjbT|H1L!eJw#}WgWz_4OESawPGes&mE^6E^ z3kt2ermz{Z*=AWbclB2P{X0F#XB6xJRLx2{l4OegTwzJ_7E8dhYZPJ z45iuP?i2pTXjtxwa9qls%`GvgtD@ml`BPJNDAmr!gd~&txL{W;Q71B=ad%s6MsZ)m z13c7_KvKg6#5JTarC}N~@_0lHNM@rbX_&sSa-9{r* zWEk?|{l3zCabs`Mus1DE03+Q17zU~o;d0_65UczBZlBvu);a7R!GJ8$Ut#D=F;&?>&Hlrjrjq?zoC;1RLmmimD m*heJTCk(UCZG9N?Q-^TV^UmNF$uRwWj$x2)DkbbANuR&Ex=Tv{ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkHttpClient.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/OkHttpClient.class new file mode 100644 index 0000000000000000000000000000000000000000..8c5f7272b8b5b98b8ed422456adf74fb5147d28b GIT binary patch literal 9240 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 LhDvB5)~oyg6)M~} literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$1.class new file mode 100644 index 0000000000000000000000000000000000000000..9c4d7efa04b5df7dece7c9cb4ac0b80f8036e553 GIT binary patch literal 212 zcmaKmO$x$5429olwOR$c7r}*Vhn_(cT!^427{|~b>rC63dN>yzz(a{CxHgX@JjnaV z`}2GONH7f%hKK~BvuztqySyZU>51x=oL?8}p#)}Iqf6^@lOD)t_8MX$u+a7{UEQjN z+Dh76=6xl9xm6+n#_WxuW>YHX$O*(9O_s`}@^~podx7~MNW5f3kH74y&jPyu1Kt6K NJjdJ---yn|qc2-6Gynhq literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Body$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Body$1.class new file mode 100644 index 0000000000000000000000000000000000000000..38271ef07d5781c0dbeac85a7533dc335608c4f0 GIT binary patch literal 1112 zcma)+&u-H|5XQfCoVZC`5<&@-0{ue(Cn+_76DmR?RgsEPD$%Hyo?K_u7!q%4uM2$u z?uY{icm^bpC`cUo06Y|8Hg$uGB8nyNtY_!9GxP1rKY#r=0?@$yEYi54hDr_@+|1z? zZX2)+)EEl;POst$Uvgiz4+flJw&jYx9qvU=z@vdJUUsD%*z3IGIVxb8A)jCvwCyHC z=Aq|%@)1MDIs@NsR<{`R715zwg_h^@XHkEL2W@AkN1jqkxK3}&2|V>3J9XLhLV}v2 zbHHG(`92R;dQKQ}@`93%&H0?~MLd)hMO7NA?o)lvTh*~xveU_!XmNj6b{SGu^(lk# zD)1z43x;W{^}^YAY){x5ksL&FQwH4WFRK<)B9aW{@c|6E)z>Z`NKg2ofjWI}iYRdT z6HlpN#z%CvangPvZ(< zs)fg7HL}^d;=e)vQ+#f?@PYdOINYRs92jpx2xf4Va$h4{CwrZ=m>s5{!~D>f!2(J& QD-oGN73X#J|4`4wZ>!7r`2YX_ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Body$2.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Body$2.class new file mode 100644 index 0000000000000000000000000000000000000000..250fd4af40464cd1a50f01a06b48f3fb54fb1dff GIT binary patch literal 1669 zcmb7FT~ixX7=BLJ&8EvjCqQkIqkjwq<=zv&Nd{$$xO$c**)($`#k6Udd}`&e?NKx;B9<)0{wVb zJ>D~s#I%X`@qx+dMFTS?;+WNm<24Esm++y9IecW|V_Y^dj|Bst7+4ZW-m=|v+4lnJ z1?#t~Qs7*v?CFc% z?^kXMSOw3MwFTF%*CkgWknZaLy1W_6dXQGE^b`Z`J(m1fCfk+PnSNiBQIg(nuqV)y z$rc5SZ)#2;*L{Ihrj^=C7*xYxEvQL*e^#X^%Df9K({{MCBWnV&8}r=34+DXb?lgkk zrYAu^F~<`aZb1uP+kt?&_-$EM1IPF32Ci_v=7+ViRJ~z|nz>J?ma)u>UfK2Qj<>rk zgFU}u;ZqbW4B(`NL7cKMgrb4ZEaWg|QAJ|{r#qY7;aOoz29_;c#fpJz7FKcHz?y}1 zY#7+I@HxH^INwcJ#~Wf`OJMXxIDu0~krY;1DYH;z7CK<6tN&AcU3=ac8HK_&vw_x; z6v0t38fu+yLFT?Bd;jXjrlC~F?8gnQ$c(k ziHu?+tWZ$S#=6zY;c>2cwwvDw9G5YxKFih6k%7yjGSZHDLA_9CDiY_}ZhJMWfJuH@ zlKh;+1_qQy0FIOiS2W&380L{1p>+{4^l(h(#t$KK7Y-52-AB&>mtr{0XPiLbC%nX` z71>Fo@Cs)Fui{*Dn>ZFwKYj5dVC=mVJF{h652Q(8)Ipm%FJ z9{Ul=@s!>(9B;t7^Ut%C_5gi%&^Kd5R?2vKKqpClf{S!eL@64dCpUp!uKflbcUhSO zqW-|kxQ7f5F^vW}4{-&L$au(u^*Bmmj`f^kL(+JiRt9JA2HxZj48EC|vNFiBAUdw` tFpo$6mv8}ZG0h1gHNMNUX_K^L{IyI)Ye~F=v$O^y{36b1>Sv>_#J?hMeW(Bc literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Body.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Body.class new file mode 100644 index 0000000000000000000000000000000000000000..9bff9ccecba5815df9a2455efb80a628b483dc35 GIT binary patch literal 2314 zcmb7GOLH4V5dKDyyz*xKKyehmLS!S1EXP)y2MH(&L`DH8vYo^aFy@h!G?v$qca_yF z;2Q@Xr%?O>4p3BaqAFbE6s{sSsNzQfJ-aJeb}5n3VQ06e`|IzU>7LQw|NQ<3fLT;j zj35*G*Z--wfwvUAts;bseB2BpE5|wcct=j>RNTV5D&E7qiecPVa7RI2ML#kM7Q$Fm z5y4UzcNN@I5ygE4%PI!3qF_zI`wYRXRoZ3H=1r5^a}~W-<242_bX_-0L)>6Ek(gW~ zzd5VK8T#^u$rqiS0=HN6LWL}myj9dIYr1X7Z{HXcTL!_5=Zn@(s`kjyZSGW4*266! zs;T?@k;7{uE;FYYP8Kawa8s=8Rtat_G1)d~ftL(jx==)qACc!~S!}rsZ!;*L+lJsP z7Q;{?zpa0!rwl8#I!W5d9!tW#PB=|Pw~Puu-m(NY$(5n^a47B1vgO!CE`g{j{k5Et;xwE?Ou@Q_ z53#{;=BVJTV^m7q*6{E3E7@j!!)f`X!k5*{ev8a7eZ zFoUZM@kZUeXlob-4|3n6hOuQiTLtVD7Cf=VNzrI*3_IgOXc3BSF7ACF--gI>lU+@oNDTTkJo+vc2nRX|7L4G-#;uY z&x>K8LFsVggsQS~7%sIkX(GQ+F!AxKqm4*9MNNH&a9b9)!6aPfBI}(L(RNwo>2bQ< z1f6N|PW?%JPHq=ExgG9B88XsNtKXEtF}iR@=-vVpx-Y0X={ZJUDH`btK`6Ng_8Ywf zFiy`d*I2uBr`3r{j5nA6v7g>}@xQ^~R)TcOkXG*%%q1Dl|kUaks zy-ybQ(NCT)JtMGjT*77a`E;Um4Fg}2^(#vDHO+j3EBMx>mn0f9B>Do~>jAQcagkyJ zk_5@UOrw0eg4YREQoZU^El`~Fnn?bIo_$2tBd7K-@NBB_by|MyBf6fP+QXSALE4rO;EmBKi{?gmv7L`H*_@LkCg8x%J=hg^1XpKDNg`tm*;hy YrE!>;4r3Lg!EX8|B7b4}XX1|k0eBu-ZvX%Q literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Builder.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request$Builder.class new file mode 100644 index 0000000000000000000000000000000000000000..210af7fd289a5c74b27771a41241e54b9ab3108a GIT binary patch literal 4187 zcmbVQS#uOs7(I8E^rX`yVPHV^NeGb4giOMsvda=6lCWd}BQA7in#n+?XPD_>(J1b_ zrM~(ru*xJ=rb;ZW64wWp7xhse^+6we@PYFCx_f$tq%#Z@RrmJXzTY|Le%tNv&FxP< z1<->J>d}U$czBwJb3CX#jLF!5WC$q>c^SVG| z{{{83nlLmoF*4Y{OQ3E-Gsm+jfw28XSB-RH$joPqG`*F^H8rK>3j$sJ$?Qa;aH*)~ zwPG%jy*O@~xkSb=wY;I~3G3IOdgZ9SpG*T|+0-=&FVNEgdJ<6j3`5Hw)YU>kBfwTq zz(MU&Q7f2jY(gM@Q%&C~?ZnsxEorjw-5Dce?iGl%&sW}YnrIJZQ<^|if5y;`7bnKF z{IEKv(@MBMn^g7FYCglioyCATo*`Azfnr9d6ANspuFu{^Iu<+hC6_Yw4lhYH;t5h1 zEk|iU)z4@16IzPG)q6Fm<;+ahAlmJ7X={Y9vm+{S%tNDxBWr{W80rKG4_;RFBF*(` zDrKjFfSh;JLSUrb6L7&i>hRp|W{DdGe_AsIHnrEfKfrFF9LZ%1WY_1d%BA6CtQFax zD-z;aFYkI)(0y^-kzY_;V_Eey0kF1a3cC3(>;m~mybTbbl;sZo{0m11|ZlKO4;=?1s= z$wS#3f)3m6m+6nK@4#P?dVXj5t|fj#f#KXkMs@;bl!_c*nBq+ z`-rRZ_F%|u0&Cqh&t65H-r8UVvQO8ww5spVr;8JsVY&@XV0n3yefzkLxXFc$QcCTN zDtHMmD|iL3QWBS~9OxlaHMI)d2DY2X{zEjK zJTXMB@t+(SmhhH>xABg^M*DUw0YoP!qxMRdt{G`_yuE{8QJSps@~9ISCVNj{eU&Y3 z?rEFLC$hs$w?S1y>u&Y8^R-i_=5m@rwY}M+`#6xgDq9-3$l{Hg|Su@p}HB<4?yoBUYY0$Wxew~A#EP&Oq8PvtX z(i8%*S%gMsP(KBKEItkS%tw~>gETH99^e)N_#866Km=c56~4wp);kLa4`V0&B1F>D zK`hL+t7f)_d2HWSuzg2t-!I6v$zr2^;IK`SrJt0<=tRnBdU=tDLsFfDJfc#fjGr(vy!s4=oJ6avt=b z1pQZy&_FK^JE{+pYdK{at%RfStm2HDEBtSA{XZ3+Xmo`)5>}kBsM>JU!Q4WA;1Gr= zmBlnxm(l91^?xlS#opr}(KYI2zsAe{KTrEdam?Z0P5gW&;$KT?HIM&x#YsZ$NkV)j z5`sX#7t%TpB;mUY65Sq-rmT}4E%7fQ6IAp=&cUY9a0_QV=U^b#IR#&Z>#aH$b!ZS0 zBBCBEg^YEg!J_2M2lbs&owr#1hMnGG9fR|y2ge=qedG>yh{Qaig2GBmu@pfOsW^$` z!b<$DKp+AqaMA(WMj69I@+?|MV`2vD=fqd6u(0g-$~IPW2&XXUAS7sJgdkN)aE>uP zt1u2?i2E2B4`al`I8dAMX`Jye_Sa_o7)CveeYF`sjl=9Luh W&Gff=SAhSopcOl)+~1{{eDgo0v#~?~ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Request.class new file mode 100644 index 0000000000000000000000000000000000000000..b6d32941ecbdc88dec7211f05587cf938baa650e GIT binary patch literal 3633 zcmbVOTUQfT6#h;U5;C3wQnamTr4ld@Ye3X0Ahn<%HiZ_1R&8x3$ruL11d|D3@AsSi zAARXVyH*KZb*(=3p+Bmtd(WJNVN3${A?G&d`}RKH-e>3h^Y5R30T{+l8oIHh;V70h z9LC#Gn!dxMn>@M|!EK(rt098-c;yaH-{;W>JkoiT){sG#w;0^q>BM2+Inuc2lMGwBV)6F z)eP(cxl^ z_m^!mpG=u07BsqO<}BSV7YTAn zbDE2U#LGC%jV)2ehD0x75)ZH`(T9G4Q%@5oiHG=*$v%=eiMYha_(Wm=gA$+OGl>LF zMew=A7q}qtB}OH_!nnlOxGeDvu1b818Hw*OBhXvVZdCxKJ6rmm{ro{<5NmEsA4yr0#{ZnQoZr7>IP4BYv zPr8Q|wNld{=8a?1+;okXlG1;P_KJ_fVu+qYN9keJf=(_pH0tCss(^Ija zz8wLsQ1tpq((DmJGzVTC+(uw9@dtui2yx%Ch4A2GL~hc!bsNzwXuN!23zGY1{)Wcg z&$N3BZNCvkfSdtdq{kP?K!{98GSNk=z4Y!&;0z`(LL<;S%rQwTBQzu9IE!=S5EUt$ zSB@o}IUQ{9cZ7bWO)hJm`| zNOeI9UsjY}X|xJD{fyT=r>jci^1McDlbBMcJdYraCxOy3gRlA`FpU|7-z86X1zmmzmK(@(4YNccaJ?bbAwSivJ*Wooy7J1K zJkn2d$8)5ewN-G$ zPkz@!-sc9ZgD>*DBELcj6y(qhCbl7VF1#D6eh1y-?x^K-7;ickn*;h57KkB$MJLEN baGd%hwEq}YFm$w1QRqewqIik=6QSsTnPNwv literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$1.class new file mode 100644 index 0000000000000000000000000000000000000000..09bdeef85e06f44f4d05b589a22cebf63e38a9e5 GIT binary patch literal 215 zcmaKmO$x$54255`I$9Nb01+3i9eM^)a3O-8V634()|uLwdN>yzz(a}CgJW-bCF!aOlIY444y zxv8YNX3kae7hJ{!5XL*Lxn7sbTDF9!#mQ3XR36R+Cyp@tM~N1m(eaPA)%AjR0eXH1 P==(YJ9r_z;T{QRtL3A}W literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$Body.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$Body.class new file mode 100644 index 0000000000000000000000000000000000000000..0911cc6129f775264dc36aec8d5f760b64f422ce GIT binary patch literal 2397 zcmah~ZF3V<6n<`+bldHgm$tN&x1@lY6x#>_0!5@LR9izUP{2|JH_5hLNO!|#gVZ-r zzxV?fUq%II)bXR0(bTby_(^B{DgFrSb9Xmsz!fr+z4xAb&U4N^&pG%0_0KQA0oaQV zRqVpJik)~lMgeZFuC6M`DmbO08RIROkmIEMydpoRRm5;6MlJ6r4bQ5W!Z{V^aiImT zDwtN$DIuqDQO;&ssq>nG*QM?y6`OHc!5ea+tH>d*Vk-)AX|&R0R>d6V6e@tZ5k&m4%$)OzF8IB^_Bi zuNTkjjw#oHFzU{mWg2Dd!lHmSW?6SId zu0XuLn<3J$gt9@8 z+iD6HDGj9Q5r3D8@y8}iJ!@B-yfJD@irZ`449Wy)coI)(*pCAOo%M`O)(K)NJ!wO1 znTlET>TGaCw=COD>WIQozJBc8(iK0i-k%WdK7Uaj$VB>`JT+(n5 z&ndX3!9iJptD%DH0;v(dCI)^%h&`;X`XUgu@En*6@xW`nwwT;aLsu;iiIH()N7?AFzNQ z+YS$)Pv))|d2-yWmr90J5Ew}M_0^E@p`ex8R45ALR4rmP9BF$mIwN8%q@kQ9h2Zo&ubo&l=tRObMg68REC>cAqNkw?9KF{?V^36Es?XB-$Gt z_!%2|qg8B-+(o-I?&y%Z14}FDBuJO1NTp2|2CC>@qCfv!`*<4QV@B`^+VLqP`kbfv zf^mO|A>6?*?(+5gijVNuxP))`h<@wkU_UJmpbtl=)x`f+9L4iI|0S%$F}y$-PvmEa znsdB0k3W=wVPt{~oTi3MdA$Ee^!$nL{uOMVmIosRz02706ME#%TF~n}`0t@$30rWl zfs}aQvQ7q5J%ST~BN?D{)VYGK(!nVtO2W@+I=4OcMrVVH>)S9gJts~K_hsHa1o4QfTK#uPMCN) G+WIfj>rFKP literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$Builder.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$Builder.class new file mode 100644 index 0000000000000000000000000000000000000000..69e1b412a3e6e883b115a5e576f23298deaefedc GIT binary patch literal 3083 zcma);Yf~Fl7{~u77nUSTpeeLexugYJ2$Upky#`tff{jgEg^J>>ZjvKxT{d)gQ|ou| zD>&l^@P(ZbGb1zhr89mPXMExHjpOs|ZU~x9$Ykc6-E+?Kd#>l%{QS=kKLW_((-_WR zorgDgxWz+}hd1Lmi`xoHaVR|B>BrqTVz}3jw|MDo9yWN`RB*o^@5C|0n_CLrjbj+^ zDcDxnNqG*zfkZ2J+07_fLb(7X{{QXZA$`91p+suym zPN98eu2*iv)b?C!+n@r`$C^>6&6rlLdPxz8TSo~J*a{9%$Bg!D)$L&Le>2-NZM{3K z&@(7n=6ndGXS<6~zT#S?B5iv*m&*yPbvIzzFNcnXc=aX_dP1-!InU&|UdeP3n}SzZ zutVxv5%w!D*wKy|ZfUv7T29PkS1m1Lyo=m);2NV(Na~3(^==qvYO_|iDso-tTRYIy zxybiH#T2GhOyGiwF^sEt4$rF?#W@u-_)uUWs0nt8jlhN09V;4!+|i7i)=qs-n$Fsj zirjbfnkg{o_t^CEa@wpL2CMpr?jSeR^wM%Vr{ZHgQ1J;5GtdMk+pwFC=E!5r(WY1F zUCmCLwY0BeQDEf%TdarH$AVmIo@K>!4W_%DX(m8msAb>1@C(%N#=4ZlM1F z;rX91aERD;D&9ci+1OY9o62vQ`2$2VV+V*lb-A-NPS8IB;5S6@D+cj9Y5oKA_!Bw& zg%|KQ=4dzVX+j1I^hP>eiz#IE#5RY>rps9LExY4emdJcZ<}7@Vfy}pbGz3-`rOheL*<$ME!6wEey z5~>(<>1VvtM}{YfHBKzbJjKn+(G5DoOoamKq7VnbL>p|B zVCOo(xPI8Om+-O=dqCcDkS|k?qHe_uZKqB(ka|W7kR;w6d7w zf)L|4B_=Q>CSA2$o&@xK80yC>c-2>yrJ47ltgHp;a~FR(CLBe9D~yDfupA&9`GzQ7 z9d#4FjvE2O;odaAhMNJxq27d7uo@sNdJrbJUU!{aqs{=jRbfohzw&g1|Jx7Kjf|m8 HGsWg#b9&xx literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$Receiver.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Response$Receiver.class new file mode 100644 index 0000000000000000000000000000000000000000..5f86ffa85395239c4506c4e47bf7683a8bf2bd5b GIT binary patch literal 362 zcmaKo&q~8U5XQf$G26set6n`QDAgST}VbZgv=*`)Yv9(({FN}P(Z zm*VN0`Q|r&n9r~G4*=IVQs^lh5VGJW#uZJ)gwxBJ4KF&rHm2gH)ZzK5u1oz}9}Vva zdGHI4W$;n>v+aBfjE48paPwxltetcy3?#n|O=WrF3K`IE(W|9d8HGc_#kLDt?0mtN z-HIzhcN6xe-g7lBOpF`}gY_(382_l}4@fC~2&>Bmb~lKD8iv&-LbE8U`NelP~o4OTBumS6}JX*BaxA7I~@%Qx8jeDCnW62W8-y zfn@_L0uYeXj-%WO+w?r;8L$M5@v>zXm22R+K>NHZC~HISUI-+{OT|}|aMgNQdA`7z z*+OYG@2!_jSC!ZDr57u{zm}g5ACFR@P%0_`F-@fvWfIjB7>HG}9ACMPY3D--^X1)8 zUZX4pX1inc=9RZray*sMzEN1Zs%W{Y;H%;|eLdS$iSo%Y%dz~M0@>cCqM0ZyquE7z zG!evgc-C^%TzPd#xev@Gn~`?TmI|i5Xu6i(M~4Z2#bVsXQkYnQi~F-AaIQDoKs2}j zy5HKHWpa~Ya*5nK``p|x^S0?M=NEj}a+XK4dyg1_W3C4N?hzNb9s{x$BNkQ`)ibkf z`-`SsCVbLW9(Mwn7{~~q>|1tz*7AHtlUlHr9n&wn)Q$6^US({rTQ>=FAWX*`LuB5M zFo{8wfu#kd4fWKYHAk8#l^sTruHp(D@12fKL7U|i)h31AT@DKjHn_+ptdD|-GN~Po zueCSn-}M$b#y-7IqBplU6cj?s=Ab~!=8!Auc6X)9;h z=R02V`IM#XqV9%#p>rFw6b$lH;UvF2+R&-1jjK*wYr)K_31-$zFtcJfA3}>RQ+_q{ zbN3?>+yle89kk^7enaaP5_)diLNfOUj7MCz?;y2>v_3wt1*zwQTR8L!^;$5%@hm?{ zz*PcyNcwb)UqaouLOWOa8|EqKXJCgx-EhcG&3BdocyUy`A)3zHH<{cqi7BMGje@m8;9#{&(wrq?1o_AJzOV%(0wQZ zdP0~4jUQzQ>Ar1r%=P~TqyIG$m#d)Zz}7vaa6bUfg(|ziM`2u_n6n2pey4WfQxW`)AW1g~`5|sakl~d8?HY0$o%M(hYZBQW zA%-{~5odh&HtKMW)?diu7#zVno{aMNMrfzDajf2vrwu~8P4;WLOyN!hH4%Wmqe}8DK8{g7RIj|TSGfZ$ z!kI{Ul6Tz7z>>MX9f)fAhFrN6Xm^DYyIe_PHYihS;SuDV*cnl}P;yq?`P# literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/ResponseSource.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/ResponseSource.class new file mode 100644 index 0000000000000000000000000000000000000000..180535689dcb3b4cf9e3e4215be66cc7452bc37e GIT binary patch literal 1201 zcma)4TTc^F5dKcP?QWOlwyh|LH!ji^rB($^N(fD@k=V2eix~95EOmv&?Jn$vf26+n zppb~sXn6KV8Rr}}Qq;umCTB8dX1?#6IrHP^m+t_|xR-&1f{G$$W#nYsP%(g;{FvjB z5B{^6)?=?3q6)d zHSeXxFxaqNs~L4REq~42bm&GFSgltK_w$V%bKfjErn^-#Lf>|`Duvzz=?$-KI_suy zbI=%Ba?K7A=zpU!q!(@14wo24{z1A@SZ9#JZJRpG81|NHhLKN5$vh9}zO@(Gz7^Cw z*R|TA?YScKj6qp!J2CD;7i-;(I*YwDvP5sCp1j&an-3>@_9^H1d^BYFzT`CA#XQ5r z|2IIxC>Ata#uW|27}B8gL%4$&Vi-6bJC{o9)pk6W=yUl(R~xO(9cq^(&UeqO=9ocH z=}PP0or|Oc@)G8kR>_7k|JPejJHM^DP(XCBVagB-UM0xsRv-6kT^#2 z19=P==uC@Pmhwk27U$0+A#VG!kcyv?I)=mx5@!l7(v5bKhH+dHaheEaamq51^aFBn zcKitGk0RX7cUmsvD%Xx{B8O|8#8j+gDOQpz9zcErm5lNhvh)s8^8Fu}lQ_l9#h41F zMfY5iMbqP7^(&+eJ(E0wdWb&ZXp(Sb;q<43qolu4Uh)8a#)d@f#zuVJ$VXK4J1xRLAR@tNg+0S$Wp1^@s6 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Route.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/Route.class new file mode 100644 index 0000000000000000000000000000000000000000..0a58f62afa2843bde71aea03332e2b9759af0ed5 GIT binary patch literal 1915 zcmaJ?T~ixX7=BK^cC%U9kV>_rK%`pp0Yq)B)dXw>+J*+o2%_|=A*^I+$i~gaseiyf z;8ncx&YNE7jHEN|j2~Cd_@g>~&ThUMR)^Vh&ikJC<9VO=J>=h)&;J1M0Ul_$fSU?F zQSqsU017IKDwd;&VMQ*V$>o+@ZY%g)w-YIX;*0l%}V39bcvo=hlbtQtuwQDC=e-{4bxc>*i8Q~j$u?U`A|Na z&0Vm}N#ir@#d$wQ-t4H|*}?>3W@~duU@)B_g|TnyW|M@<3%2t=aP^Cb80@rUe=6-k zs#h9E`3DEbM%5|EaAC`-8MZ*sIyjbWxwuD-1k_rkRrB~I1Wr?gqtvcDY$*k8$7)V#ua149>N!4gNrqy7}dZU?IUQRV=A^q+POt^E{ zR|;HWV_)a5f2ZROOzF6YH+8&)OFE{Jq`lvmyXa(s83kn>i&#>ysbEXThq%U>A7b?w zA}wh-U9XY1t24|&Ql^17r$^% zvVwqnk~IX~ldK{{^j8?et0B)_+K02hL-~~l4@AUOX51vYXV6O`nEEO;l7LZXb=>)e zuk(9I`#49(oeRFs8DxE&wWnjSZ}~U_IV|*?H{g|*dV$!!tec<8FUn8*2}T+028SO=@QzYyD$@fY}YG10-2%tT4;;#>zQnUhkqi}M{M zWOhp0&piZBgTulSY#ReZ!3K2P=a0*_3ns;cItuK>yxZ*3U=&JtpFe4`xqM$efIrY$ zj>JlQvKXIB)+Dwr;*a_QVNDJMqDnj}CMBv4G-)nrp=O9`nnVJ-jQS;?%pQmKD|YB> a6tVB3yXa->VG0uGb$sMvxC$Dlc4rCkr}!Iu zF;NMcnE2|CGTzx;+8S-sz|C&oLHsL|S1ec$$;1$S>UlkGa(WJ4Ug zC*)c$%}{d7p&OX+toMQ*Sc={kK!z%N=sQ4J41?&QHTg;LGF3Jarxh@mI|IvoN9^?( z;$M*X6m(yqsNN?qg#@NCLMtQe$0)`qOXDiWBdi*A##Jr%8Ht5+^u+LL@h6fWFceh2 zLJNy6@L_@lW=ZT#l9a&=y>&%069Ppfisl+70^&5TW0Hu{BxyP#-lklMG$P_&B5rYn z2UsEwGr%4Vdz;t>u_^2{{cc2vk0ZoXgxD9uMV!Z literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/TunnelRequest.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/TunnelRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..05b42e5a7b77d6b999a642380143dee7dda1d37c GIT binary patch literal 1654 zcmb7ETW=dh6#m9`?8$bMy4yRX#ciRry>YfqFF?|yByNgLjbjogG;Lot&NSJw-F5d; zN}mx=h~K~i60aZ;2N9`#1BoBOPeGj7HL;3aq`u6#%sFSy`R1GX^Y7nY04U>ug0q;; z;0ni81qoc^xIT(Acwa6b$mK)1%w#aDK#`F*6sVZyn3HmzXv* z+{VY!u5#2kKH<2-QP1Gh3>pln9oG*SwE83SscG1zvu&&fp5<)M(q6~)XphwxMnhkC z3){kxu^rES_SHfd?6{uw+zc$&VMyPw94nY-n8^>8stvjZJ%x2TvEptChQoEs5smQi zrtn(krcEBL?zT;P-SjMJ_nfI<$MP92)Z6Z3!+#Q*o(MaJ`^8QWbc|N$IKo~LPeS1b zG|Z805%jF8Ft>z9nV0j0p}Ce52+uKXBdWAwe%Z^QGHFlvp-m`Ey=kVh>V{rh+_s{5 zUTJSig0JE|EHj+#UqmCc?WP+wv-GSjIx*6!ys_NeT+X3wnbf4=4z8!a@eXn-&f&a@ z3sQR*Iflt$NWE@ahLinXVp1%ImQBzx@XB(du~cbM;m@!_9GQ{IDiI}DZMB+4d8(|U zg*6rHvcFU{V%dnq)6d{@6?d_r;vViZC~HKmQjc3lo040l|Bx#idn+zoX*)(ixg$iU zv|w9Li5=&Ljr9t`4B7rH%bSm=3_~(6Id^;rVWmH9b~?h@Vkiv@7~pRY8luQVzE=33 zZ63HWm<-2=fBm)&-rcx=Kvnq=UNhgpwXFq~%`i^VO zYOt5WI{i&&=xYK}$bu+ET2`_ul0>XX61PYuz=(|(X}v_&4@hE!I>kT{muW5I z8m3X8h^z5wOK;Oa6otHOVC{!}C9v4hfjUfvJr$kEp3jcc2|ej|Wu()3 z(zMJ##{v&JUO05)SBZ>NGIGQ7fiWXj2S!DK^xen3*hJDZM~N9F=Ga6^4)+8KZz63- zwwmp1b6*-sO>F`D;H{@dMu!36HE*E2^TW{WPgIw6JWZ*Y7VP6Ni9Gd8r#jdFwe9{( z`C3+R36%;QY*nxTTVOfux;k{*M}HOyR4JAM>*GgCFKr9#{_Px4(-mCP*WRL--?%4HOch1LbcMu!2>>*N8|} zS*)*cdJKPxe74wWeM0^{s$XH9I)w`qf6O-2I0J0a<2Hreos;WKw#?W9SFujw->%92 SK*YT3dvlnnYk_Oo)W&Zd!;=UA literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Base64.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Base64.class new file mode 100644 index 0000000000000000000000000000000000000000..e040df9cc735fd85b146ddf3d70da259aa34d28e GIT binary patch literal 2649 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache$Editor.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache$Editor.class new file mode 100644 index 0000000000000000000000000000000000000000..5028a5b5b14ba56cd5f5fa4fe2962a7a0afbe6e2 GIT binary patch literal 4964 zcmcIoX;2(#8GgEZm<~;cb3+Iil1*4L43GgrvV_SJvjhxEz%?NW#5FcU3!MxzWTqz} z-uJoQXQJ!9;<0M7E{Dc)tK2GoSo+K3pITa_mOu5stIyj#N8_T!Y?Y~^-|u{%_kO?0 z&tLe_PXP4dhm~l@Rry?#PtxFLQAQ~PhmbbVg(U;mk&#hWhikw7#sbg7g z-I8N(l;t<+c(Z{9+?18K7=!BU&~dd|w&xusb8+JfsY#hjFDXHr%& zcG}5a8_(p1t;B-e=3R*^&~IiO*R@j$)XOspDi^HmNG6lc5L=NsIWEe9Im+lRIN7!y z1)bZ+Awu|slXBc41y>?v+}r-qyeb_R6oiJ;bGCw-aVKR@@n_rFM9c3UE3Q7_6sGuHuDX3D23T*n0^icJe!e*v}Y>ad1Tqa@rkz5z7fQKdG zOty$OcmzWxzJxEE_zIp>&=fo#%rFyQ#n*Iv-NaM) zhKUt?Q^A=snt)f%+Wt$A5m~>bpt%4Z1ojir#2Jj~__m4f;AuJjT^-*u@qOGiaSzX! z_yL|Zv5GYl>)0@HM2vkA4DE&j)3H(-D(ER!bk+uskykh-XRq1`7J*n9T>Qq_x&0eV zMkAkB$0We}%L;ITi%VQ~Y#XtZ3cUjYc(@F}c!xBTytogSUj=+|%P9hd{%Epk4JU0Y zmCw9j!;vMH@VZE`ta~d`@d{br>j~RYIuXbtR;7~9iycq^PnVijkc1Jd5ww_?2>Jg--Na+<2%opmrT!s*Z0$dbj6R$EH;y029|7WyKxlWR; zcw%^kD21jAhBR&*uP`LKBW#vN*>uPk!PZ-$99u^*EW_=hh;2AN@#YUeK(paS*MrZ}pXo<*uk1M?_rD^Oc2&5LuBJM3kA(+qGn z$C*aj7VTU`MRXnEXxA#VXx9ex+t8I2RCaD)$B#p+Q15x%j`LfO5CMLLO7+*MR)2$o z>TfZ~^+s|dFT`BC8YagO=|lWGjgh>LQ>0?mhA4%uJ=^s&7&K_z3PQ?VF8hKQq)`8ku=rC+?$Rx_ccD42D+l&|rnI z*ubteG+qquR1JnVu-o%R({yxCNLj}oae+=3=;DHYn)(!7Fo8?B?73o=KWKpjmOOeL zIgk39KZ;sv{!hB#1-js0Xx0?8X(~Fk5c)M8Ls}h9X*)2i8JN&aT+(WBS=))nwHhR} zdR*5UJc|t>jK}%+O1dXZ>+JU&CDJ^CS7Dqk7~;d?ETv+&V!3G9~yiC6pfe+n14Ckd724u7Md zm(Ejeqg8wuWlHV$23~eOxP}84DYLf{k}c-*!BRdq(|pj{p=*awt3_}?i_#fg=+U}8 zAx$43FJw>*KH2hO4CKX-5cBa%{Jl`u`cbJJ4e&Fz;CG4q{L1uNQmH1j^P)Y2tTv2}+@RMHjlaAN1oQmCbT=9yWj9w25TI~+ZGV*=qF;Y1tsil>Y zKgim*ZUq^#YVz_N>@6;<+q?V*%;zu1sg@W}kG9OLLV21)-(Ep%zha9re#I7L`p7`V if_L6Q2k8OYr=1BLK^^}~s~u79cX8g$PH>s~{P%D0WZ%&M literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache$Entry.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache$Entry.class new file mode 100644 index 0000000000000000000000000000000000000000..ba43e641460a07f314851218ce40dead6c9cc36f GIT binary patch literal 4472 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/DiskLruCache.class new file mode 100644 index 0000000000000000000000000000000000000000..c49820939a662b218e7170e833d9f10396e9d037 GIT binary patch literal 16738 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 Q?HT$>_?vS@PkVCz542x2lmGw# literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Dns$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Dns$1.class new file mode 100644 index 0000000000000000000000000000000000000000..c992d9442225a4d771d8a3b16823c06ec2ca7b5f GIT binary patch literal 652 zcmaixOHWfl9L3M{!L8RqD1}Z z3qOD#%6R6MfQbth^Y}l0^FJr^`_Io`0JgCfqk^X~7O@oJS%l>XD*{t*w9)>pKzXBe zAyC=3T_w0wrx|HUC3OA_$FELeeDDwP(Lz8<@=d*PBF9IPVF#p z*JGKh@hGu_zW1X<8?SOBv*ev|>)Sh|ddlx++1{69IpmDZjrNuND3eT@UUKSlZF)Pc z%Sp~CpB!=9?RInJ9N|jeIv<4n#|Xp+pHnsR+8P&OmGP+^=c#(HgOwV`Zv}`x4@{a_ z$3Y*I@7r!2Q-~rwucLvcz>E7`2sH2JpLDKNN=<9`aRMs^6G`n7MQ!O z|Kl33Q06BJRQaPNE~;fz<1OLIpFs8HcZhFA`9aYTl1qrW*C!2lh#5vSk0u`p@M}il yx$5Q*l)my(!X3O^!1I%a8IJ^^^%+B=Sh{8~FTw%6nsa?A z+OtVtL|xtwh)H+CS>%bP9~U-BIgQ7X=0%c^%USFqmxYZK!@;8K4EcXQSN)OjG{gR! zitY5|ScZ@CGF1A{3PZ9wH<2X$Sfb@K6ykA|874_bCf+(#CgC!jtRP2Oo|q#T6oJeK g*v%V^S0rAjWLTw`Bm{{!utsQL9Ts8yr!f!MKfTX&Q2+n{ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/FaultRecoveringOutputStream.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/FaultRecoveringOutputStream.class new file mode 100644 index 0000000000000000000000000000000000000000..5da1b18f81de0fdde8da83f0a0300697650f13ce GIT binary patch literal 2434 zcmbVNT~kw66kR8|$%SyKf`EL3S~c8&@qhRFX%=x%ypS{=Gd+n1y{{8g@ zfJ1O1Xh%ZFKm-9Ks?ml)9cLm4;jG*Y$>E$F&g)24;X(uvT#O)vOA!oXL>gX}16OUh zBEMag!>HVj$>Ewb9+#`@I&MVJjD)nG&~a18ErG^a>(NzvE^EyX_|wz2o3e8mZ$>~Q z1q`?1K%gu2vGu@;JNfv)yk{p|*P0*ky*b|-^<3MUJs}Xx`<_5k+3uC&@JT1fC#C~ePqPCiGH;YpP!fxxW+?();q1)Hox>Aaug94XrpR%klw7nsdpRC*1iv-yII z;}($!G)LbUq~|7&RPxjIteq<*c*t_HzRUY{uN?{0I)xIyVzL;KPHIb*#R>_uY{c7? z1BtG0Xbf8n9V@t6~cOM$)Lbrik*lpl8?g;Eyzf(bgNhm0NcB|}9$(tYPxNE?|q>i)! z6EOo*unoM6qXv$k-@rR^cn_xyoWv;u)5sV&4pzVGH3Fla<=GYJXK+g3*#DKIz@aU# zCML z22n2+z*RujSIsOj=PC#m?`@8IxtoVZTVTJr3eol>YMvu7v5MfD*|rSLe2&mW+bY7# z(9PauR4pk-`#82D%rVaE2eF-Ra3c;=Lr1U={n*cw?xI^n(Zd}BC^$l`B#;2=q-Hov z7=O}Fi1Tgp7gRq%?Q=vX>T6bEti@imcRWKazgNZDJ67-(SNd<*+ac!_Y`e=@`w2Cs zAjSn{s4K(mOUE^{MO#JPQ-oWzwS|{2$hjF8`IO852}$ArYB(Mxlw&+ONm!=|_kC(M z!QUC$o}=}7{ud;16BiV*egYkafnM|xG$EHM-lo4eW5{m@nfriR9pWm;u`1xge0xw4p)Aye~+_~vQ(m<{tOZ+*r_ z`JAos1*3nd@S2R@MV%jG3WL1WN?}Ol5>vV8(Nco>?}-y7{cgtNg$en6XX$ zS**#|?pBiJI6%m@Dg Dn$7+`K5PcKYjNp<_P@*veNt9hMYrI*pyjbN4W0j$}{?#E_*Xoq zN-^a@@BS#uo?S?w%pr%J>3-AQ@6DV2^Y`a30Q-2FLl*aQ*g`pro7m2wf(K@)nq?

yY>2-WkBA|0sS0mI_+Kn2kYhFb0a0;j?^vD86*s$F9vO)1CvicE9wU$hDOs5hu-KzEVPVIz3_cMicY;i zMN%s<@D530_ie0{=`_0Dg?cC=A``kt?dw-)VaVuM(ONUAcsS^qDHO?1(vKsGaz|mT zefcU#)Xj1188d9;QQ~lH6yVyp1)HO8qk+dZ_Tbrgf_)ozQDShfFP~xM(&^MUa{m&V zUURN4eG!Id*L;VWr@45{8QNA~OVMS>`?1ziMbo@cb7neIlA&av) literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$1.class new file mode 100644 index 0000000000000000000000000000000000000000..620e8da2bc4706497f77435173d55c759d4b9fb3 GIT binary patch literal 233 zcma)$O$x#=5QX1pwOSQ>1Q&`sL(d=zE=0i-#2Wi!n$#rqa4tN6hZ56;d*3i`crbjt z_viTnkYF4l3=t8clWt5ZwuKag$x(85)uvjN{J{y+jY_4qh06BA<@yq0L|CS}V)ou} zBbu7&Tkc%V3gv`RT(Tcwo)AD7@01c|ExEPA65^K2Bv%%vT zm%RFHRfJTm#HV~dBvpw?RZ^Aj%HK%k^vtk32vkTOwx{Rz?R(F;eQwWw_4h}g0O-Tr z4EEyH4EEtt181XhxGaaU490Oq#cL|ArculwjR`qilfIJ~T*vDwrZSkujSSwvn=0N? z@pcByct?eyVkU!DlvI>e2nEf~qOgmeRdh=8!XLH_&r`5_^p>$?=$2v6>VauMK||4; zwGF@Ga#PEb>t}L%kFiIWPnf^7>o03o>4H(GKQbnkY>a7ATNcjo7Oe^EDWU%0km z=~pbnzv;LOhpQ3DvTc2;yNhe-E^Xi`OSv_ntyd(~9VLfQOMZBmgc?P+g|COUD6}*b zIE2Qba@pmX4HRUIM$;KtE{R2-N2s7ROlUfKVZ3T4p@hc*cEr#WMXBPN{@u7!y%&h8 zs;3wX1*#EdRd6s2vpFUOJ0nsP=7Ml4z5=D7AXCl56WJr|-~=siWZ4(C6d$d}Lh{SH z4D5N9UM!BTD?%XeqVJma?0{shkWz1q(wfQ&_7a66>oH-tv%;^YW*xFI|AJ+SS;HDC zl~~NUQ+wdF84#9%Rg?Oca;!C7gi6It1yFE%gG&CFM7Am1zMvY3<>Nf&bIHY1ugNa)T4#aBlq_TM6 z!RmTZ^7^UPywkKhBh|<>^BOEHXm}B)RoEIFEGlTKWf-5i#imhlTZ0Qvg|DH4B?bAK z%fD)Y*Ido}YQ^@c)+!ze;*NsOn#bl^QLwM(GUR!}m8u(YUB{InmKEs#@$OM@WLrBF z9Nm`RVd^2-CA(!;fV9@qlyX#ZcJzjOXWbRk8kcjd0UPAyKWtRw-O>~HnV55(JF>+G zx?@dJv#z13eXyuM(<|7XZ`dV9TbD6B?t$)UUQD%epK}~b7`*b-CBv$Saduu?*K|Bz zG>HN@Huwk3+%y{I819U+>ayZ;u|AH`Q=PzP6RfYJBe=2HDU|B4pvd-ILo6a z!t_2p>*?*FH={jw7 zk*y~%+{50nhiIPaUB#Y9oVChX8yP0Bn^{kDl+R&SHDsDYhS`2()}OfYGm-zo^*`zP zEBf&pJ%7h}{DI5(D`0(!T>Dv*ehiSq`CxX2Ga|0C9wY0Q0@h;~#91VoK&_mM7*3O) z)IpjI2~Lsv2(i=$dmdHu(5D(RO(ar}(sn-5LmDH29;EF8USZq>E(XyGILc=;-=&_P MCC8VguA9>T0IOT%!~g&Q literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$Android41.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$Android41.class new file mode 100644 index 0000000000000000000000000000000000000000..a31ced9c4903dfc3408f3ba19af77e771515cfab GIT binary patch literal 2635 zcmcguT~8cU7=F%v4Gcqp6)2#^rS=1Mp(~VC>mn793U;B`rLB~!VVS~|VP-osR7_0# z3Eq3H@wQEDNi>Sr{u8hKNHp=Q`ka|vb}2N{q?&Br^Uj&~<9XlrIcN5}M_+yeU>G-5 zv?8yf4P%Ye-jHHkii;}V#Ds!L6;pUi!L)))Dpb6!U`D~Lie|i{U`Rnh!JI&gXZZ7F zd%<;lr{q|kKu_Veepk<0y1kZlja!yc^0RY>zwWH&1v=LP^P(ZQjn%4~Kw`|aO@CbA z!~Qz|DNFafeBH)l0iW%gf$IXXDQDGSSq0NJ=C?Li40lmqvAB~gI3?Y>uDhmuu58Bq zb(1AGPS~riW3G-43uv>pZMXq&gRh1QC1*41-PzJzW2>BXHr9Q=oHcFVaBbbnE?ByM z%W*eP?L}adl1|yMi=I_v>kTSS*Bn z$uCdJfeFGqS%+xWvWzv|nkbdnmFex0QTEvz)-_aTRE0fj-{n-L!J_Vxn)UVxFKE9& zci?y!0#4iB$Nk9iq`-+MLmpV3RB%NA0-qgd?f=%-BT{lWFZ&zWepw1KJF-0@#d#@4 zrN{{k966SNT6DJDl5xqD$Emr>{B!cQ(9nTSDHb#&@tlTsDSGjuf_F7sMNy!&cB@=j zxy{={!J>w1AjDMd)#1|@=&G4ac%I?Pkx#p>r;w9Wh}*qn29BDi@k+db76Y>voBB=%|Mj z&Nn}BbKl&ma|ypC{9>3qyc_hraER}6-C?hWJGk|PyrfiDeayvm*Lh#w`avb9k5o2N z{Fb)yQyU?nNoi_H$!e}K?vd`4$NBUz;z)4qNM{Cz#110q?$`rF)7|k0h~4LlD7q+< zbOU}s1AfFY{KQZ{qnkV9p)-1Lf=>)1PYtgZsil}M5@>zYqJbu%$VeRlm^e;S*DChC zc!}C6?nH2!S`ud{CCD9SkzTp<7l>ybBJl~aQIBR~Uqe}n4i+Dx;l}4UKK~WerJ)@( z?NV!&+OggH45txZ3XQ>E6l%UI29Y>GJLnr8m6hF&PV&Le0NQ8bGLQbIwWXh2#tA|uoQdz#G) zu@BHI#NJPhSoW}whS*!>Xof3@UACRkp-FCZ$GYP?5RwvM=0s5G_d$l4&~7i9hLH*l zG@P%{Kx4L$1{!h|8fbWhT3qJ9t9Xt1BDfG_cpWcr?P14SaT(9^A7GX%S{umf%b17y E4-j~*s{jB1 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$JdkWithJettyNpnPlatform.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/Platform$JdkWithJettyNpnPlatform.class new file mode 100644 index 0000000000000000000000000000000000000000..9d1080e82bd75febffe981ca00f8322c54502414 GIT binary patch literal 3757 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 Zw$NSTpAId|Lh(O~7PN6};Mk7H{{Vxa&KCdx literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/StrictLineReader$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/StrictLineReader$1.class new file mode 100644 index 0000000000000000000000000000000000000000..a87c31be4dbdc274e86886371f335ad03c27dfba GIT binary patch literal 1242 zcmb7DTTc@~6#j-57M4XSf^sQ}Qm`$TrQ)4ifFNlsl8BNJp0?YuU2JFT?5u(RVT|}- zeDhTk6(fnh`=bnJ+8Pa-m^SH|GiT1_JLi1+a8+Eh$yCJ)yW1PTAg4 z(sNbL6Z|1}3S7=n=)5O9wa74=Y%(^R+GdEZ`UTF=t#dvID|s#-Ir%bKdUC$&l(!w} z>3hQ%)i@czU}c5ia<%LP0VhkQx!Q>gA#d5IhFO-OUHQ5(QDo>%rgD4EbH^?_qF8HJ z6v>qlpz->H=i84(5LTEP!`Jr_AJx}-3cY1cy zx(;B7Oo?1;S9Ph#BjsHO$=JNh1(3V)8H)J!CeD$7Up$K3=0g2 zn$v%PGW7q>wM|VLNMsm>e-&OiP<&ZR=U_8b)lgCE+^H~3HI9*8)4yhkm+I00uBfHijX@8_5nSLMK~K ze?;UB;&eo{8ZFGmy57R7>+fJ_W&RkgJK7^MM3Q|$+h-U@Xn((P40C7l2%X<4?HDm_ z0UcCG1L{GPFs-YLhRXnC4BJ+tT3=PegX+aKo4JJ-TF)Qk) zWUw@x#^WmNDCRV@iCPaF846;psNxBE$JNk*k_u15CX_Wii8C^s6`gY$p2GK3d|$=W z8n)ti6wk=~Y!uJQOr_I!Ud0bI+%AZIsNw|`FDifnJ?l88o3V{j$t)=dWsWFNMijJW z3Qoy09B`^T|Q$9&c)ASZD7U*2ba%DPs1&Flq~TifTop#VQx=`4$8v?abm@t*;hN=Qy72fZ&nu=a z$1`2Wu+u!8mGi{n5!1++#{&9{bzG#(X$wL z1yP1FFWwZa@97OJ+J-ah<8Wpr$ToNPOR&POWG>c7NwK(HC^HjVgKZ{ajb6w-y zc-gxqYvMBNP?va^35CA5)fo*UIa+Y%3~v=GfwVA25*=rjpiWx0JtApsCaAJaW15l6 znWfV9fq?-95BA(-l&eQ?TtK0-G^tG#%5KgawIsnE*QaTxRH%+`;BFm5$jC6N;8wqG z{dgWK+xFptpXSv=Dd?^#WNq7=HSB%vYP6O zui`ak@2FEM7mEegGxG`4$rbVpl#boFOUF0yEfufp*e{sYt#WC+4#@gi#U-p#!Y`P- zj&Ea+jzJlY%De3~xIrd#{0Lb=^acz2rs{h8E_v-u6+hPT6Z}-i&&1FHWL3PShrcQHBXvSww)3t)NE0!}tzo0X8RJmNwF(Ku)8@fB{SvI+PbmFmn6PYYI zv&lEzpjt@?ldZ)jQLk|oU>fXwq`m-Z&6K^&G3Hp!> zzIf#I%9Z#G`Ia+P%b!p?!o35@MTApdK<&SRHA{$0Euv{T{vKMF&^#4W7ZF|V{}Wm& z(B7@e)`%>bT7aJHUx1Q~e->RpYYo>lbKCDnulr z3T{bVo=5ax>T=)m$5d7k=cfqx@Al^qB$S)^VFb)^*TF3)U>%B-x!6tz_i{(~!?>dg z?|w=ml(g~BmJ~oyzM>6UQQGRDT#=BqO~u+5v38mA82{_uhsv0*m&d(v5nRADr`GuH zcI_e_5K-&`Hu$1Qes_E8MYO~t`FTX*!%OIxk`2-6k|EDQsbIq*HtvZeF% zmp^(Tq|9IaU$V?0v53xteSGjOtZr1WIT>1@Ru$K<*e0$a(d_bZrF?f6 z(6Rb<;9p+t^4<1Tutgk)>G<>ctMBb;N?q=3T4sLaD=*5RoyXVyd{xo?ISBp?s{?q3 zTF)~0&++LzZo^BsgICvGc#R2q9mjZ+JcT##Jl^E)tCYNj_i+&w{2EL60L%CgU*b3T zH|FsbevAL$cla-UkE{5Qp8n`3ahT~jMy@`TFX)E|ULk>2YB402a21qG zd!jF?*CmHx87@_@V`xk0qVW87g1cim8D_a8w=nZH`UYIMLQH?dM*N*D`6qesB^%wp zd`uex%T**XrfZTRt3%QrCGj7oL2N76g`ueIC0%JN?Z1&OA6Vjsl)?P5if;GNGV8diA3Kf&Zu#5#$`M%;uQhk z0}@aPBtC$TLfmmoa6tkdJjA9;b) zLP;KaPjnF0*D0Th6fgFMO7H2+td>sp#c-ut> zHyKv`qwZ4@kNbzhr#zQa)r3;<{7CwVQbKBPe8Cp?b);T0Ed5iRVQ#?1D3ZT1@8r$R z+99*{uXmE!#fE8&W?o=obk6*rqJ*u)Lf=obpoVJfH+#56ooiE@l)kA+NO9~Qj^VEzk=Pur~z zU?;G)JJu(h>Aa(O0Y+=aVAyL+vp1-*x2fjhn3rji0?y)Gs%qmrE)cVbi>bmTT&CH= P6l1B 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 K8G%dw-2VfwI$$pV literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/AbstractHttpInputStream.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/AbstractHttpInputStream.class new file mode 100644 index 0000000000000000000000000000000000000000..2431e5db8ea024dedf70bbb1df5013ecba672d46 GIT binary patch literal 1873 zcmb7FU31$+6g_K8RwI;@I!=>73MmC*J8=YUp&uzN%@=iX6R6X4Xom+`UOQ?X$(3bj ze+rL0@xlu;#ARRx-pUL=is7v6I+~1A;K93BtKDD^)x;Xs)sYPYn+84;NO``%ROONL zjbnR(UH04Es2YXR*_h_7eG*?r_FCcvH;%;{SA+U9fzv}N+ubOsCF8b&j;sra2LhRE zp6^B11-{M?_a~+QKdHwEE9?qrYeAj4pRBM1TiyMd40oJbi!0em;5w~cC-l_wU{QqMdBMyg^-T;;3l-e4@CM!# zm>f3U_Aq6Ean^<1H{Z8gVQv}Nw(tcC7QV!Sfx8x}*s*XA3j$aEy(y2;oD^`__52uO zSx4KHm2JwX-=j16!m#U(bm`ew%DESLE!wC&t$Kd5C0Cy*&t^t9v9f$>@T%qbO`G2( zPpv3(b1!R`&hR&fGf3erM&EPRIorkO5XHp4)iNS9u~EcKxM08L!g zX0<<|i>>0Ub^yItIzZ+p9!cSCj_>mt0~QIt#HfS`*n~fiv$%kByv_=^gk@aDJa=8} zQ}Nw9d?INqS;UbNor)tRJ57v9)t$sW$5joyi!DNd+4=9gimD}F_X6Da?Z0&0; BU9SKD literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HeaderParser.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HeaderParser.class new file mode 100644 index 0000000000000000000000000000000000000000..f8187eeb06b420b8657f9d8a2d87999623dd9c78 GIT binary patch literal 2182 zcmb_dOHUhD6#lM_ZR`y1H#pcKp@2g%eI#iy&?F87QzxWxAW5658tf?^Ff;DVm}b!` zQk6*ERLUY!RjDdbtCkI$ZYXV~{(%09Zu&P$zdK{V72Y6KmS^rg=iKjn=XK}Le}4M| zz-#z0f+?gLF&#lWX5?m8KHia!t7p)OYf^E&5$Q(UkixkL=5aH?!+3IVaNw7Z5Edfn zKqiF65Z(!bG zO_o$+EtzvH-B?Ry^X6vK{-mN>TBV#cH;Rr^PU?oES%z9ly1NBUEojyqiDzA?MXdTx zjjaeYq|JgR(2~^+?RI5zRkQA?t0hX>vu0i`t*DkR_f=st*{Pcvz2qF#as)(1Abcd0 zr%o^xh&bkkW>imv3%aG{9es;F0$XaS!gr{6n2j6%M_dB_vdLVA?G3%WY&d#JV6;vS zGbhQ8F`j^Klq-xak}opaJcA`xv&6bz)E&((t9f$nt_LWOi#-2n7S^p~PRpA{fdE}~ z?4^0gKC}>vJV@koHMG2v%$wGx>dZaPYh_0_jg&xeS~qlOmXVISRdk9veN3J*djyK) z%!-xQ=5<-~w%V4Nkd+MKmV(<@qNADdl!8|;WEz@VqXk-zahF!t*;4}7Plr)&D*l7(4I9&4(u_5y z=%!nCyj@wf-8qzfkjaeIRIECmoGcn_3UrRv)dppAT_fd&(aadTCFqTSz(}1wISDU| z9@341_IT-I4}-Ltj}wwLjWusFZOvQP?Y~7#@+#|)Hx~j3qX)eZ=mW&(@FPU&j(;Ya z*n{{U+tJxXwB5JQPDq@M?xA51fvE;pxs9F#CBfG5Z8UkS)JwEK^@)pp4dPdX{Mb48 zo!dloAB~5A3D0uqCE`>?F9!)9cHz5%5`QW{@ecYuO{7L6JqHNg7pP)?^fRgY(9h>8 zLjVT2iz0%vP%y|VJI3ERq%ee8oX1UEz#>L)3!}*4RcM$%5lL(?9X7uJpW$^p!6kfw z%Xo$>_zG{~8=n3F)A$K9L(npXdg7gz(5}zH(6nu?1wSLN<(t8XIM2S@G zm|C)l5lODjlM!bJKVq0Ce8lFYd8L3s1V63f170Ee#uEcf_8!jowh`Px_^A*(2Y(Oj z(#Fd{H+cYaXykXPi_!LSJ;;b9@3@D>$UWb2*Q0PXW0XnX9OkO;Pq~-AhpWB^UDq?w z*7!D*XluBJz+W{4`k4;!ifCkdn|Vw0W0_&yWtb0+NHn7b<4nF!!XMEYuF?s!B*`j? z=S-X=F__qgay8b8rWfBK*xs@m3%~dl0sn67%iXMR*R^ROek*@H?z@+s<=#un5cvQq zle3B@H>*h(01I1 j5jQY{)J+#u@r>9}S7_{GN6F{gbOZJT?+FfKS1|l9kcsH1 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpAuthenticator$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpAuthenticator$1.class new file mode 100644 index 0000000000000000000000000000000000000000..fef58308a039628333295755f35e3db5ae7e1284 GIT binary patch literal 3578 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpDate.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpDate.class new file mode 100644 index 0000000000000000000000000000000000000000..671b93be61da6f88df3f560563b4c0a062a6459a GIT binary patch literal 2204 zcma)7Yf}?f7=AXl-NbO|3PJ!2tyH<1ioIAwY#>3R2~akIDQ)ADtgxC3-E17;bHDXp z^ow5+W@M(0wo^WI+8@>SIh#Nd$aLJ9ocEmfdGGIePyYVr*LMJJVB3!m5eZ-p^D?3V zxDk`FAei^WvM3|&$9+5qKtV#l$p8kiBx5;%HbGYue4}7hfu6jX?-YEm;0GBQ8IL7ELNHz|8rFPXFPDw7gf1-=S&BwhqnT(V70WCvuO=fY2|bCY z`g1*;*Na=>)V5{lxkM?e=Wk2!Yvxu_w=0$*A>3MOrpmUB7j`(R+r~o4D(Lp@S!!RM zTU}n)Vyl_?<>X2v6`xDQ8Xae})M|X`o+jbqMuTn5w#?!d)d&Ayoq9bry|d0Gcz1NG z%%F!y&RZU>vMRQjcOs@M&wMFI>5hb1G?prbO~Xp*n|X3nrxI(rWr}l+DYGag%g9OS zYe;@Yc#OTs8auXGD$=O$iBk#*ml~uRN+dxt`HM5!Y^hSTNuTTaisQB3kkfLUq*9N& zmWb20Q?btT+4*M7qG``caF2|xFDjhz?}W{wZCFJ; zA9hZQWQmBGjWUzX*USX8QpL&|3#O=0+lkC|5pxh99Q@E~J@-oxD-6pNw1(2A%{ljjbSO?3UOu(uw!aYxstQPRB(<5hV=7 z_)QGua+Aqqa&mWfXmN46P?#>4hxYdNc=PbO!)XoH^jd?pL>#d0vbV`>JsCz*gIWb6po!C9nzTfmb*M!swW6}7XF!pC zt)}O&vG;FiQ#+S8pBhC^4bL0LVap)eHPSdoRUO`<>a}o&&3OZO)m;zy=BN$x zRRt(~t;I8QUT$;^pYpLEw z?f}wjxPFIw>@__5i39l3i9g(TNZ-v4T>b^O4j>OqO?yI~KhggNN}9;P)B*fQ2uynf z81iT#kI)`J-koI5wAa`gHosb5TfwMwKe?tu2jDqYwory8fvK{dy3uqsI_ zUpY9Rj+&L5q{51K>MeWwooj&yvS6S`hs;IqO{c4D7K<(ptLG9-n wR0p`Wsh71w_(a#=!hHx?gef__Xm_e}1p%HOI~BQ0%!RMn5s=Flo0I|n2O10wT>t<8 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpEngine$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpEngine$1.class new file mode 100644 index 0000000000000000000000000000000000000000..333dcfd64ff4b43eccfcf51666407eed057ccfd4 GIT binary patch literal 1349 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport$ChunkedOutputStream.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport$ChunkedOutputStream.class new file mode 100644 index 0000000000000000000000000000000000000000..21277c1ef82cb4a82744cd074ab4bcd35668f4cf GIT binary patch literal 3069 zcmb_eTT@%t75=t#q$9)uPPi2#DG8~QV3As2Y~l;X0SrNnj2$CiWT(Lg>0rqS2_GFL z*iD?olh-`-v6)Gx)0aH7FLn#|v>pF|{*=D=weGj}5f>+pJIw^HS0KXC0hjMFKs2g(N z$g&bg5jW&=NhnvSRatHdTNbJ!FK)@QW@6n$O~IJGn44D!U7t~iFU(zCKAU|vn_p6B zpU*B%=ay#|E-k*N5H7o$3T=&gan1G5H+_Zv+%4xLCsV0s$Zj(1tE zxmjDwxwV^qSwUqLI#!yitFGsk^ohbNyRT>N`0ljlId{INCOTQERs1Q1!QtJz&s@nK zx-9P3ORhp!u2ORso9ipCmv>gGlyv9nMW=e%@hZZ%goa+6}u?WW_o&5cZbt?c_7nM%!fy_!?aXl{X`yyw&!8+Fe=_#CZFN4(_t z&Q2kXP6)DLF%*DhaQ(jcIUM&+(+VnYE6=YFh8|92Y4PKgJh%~4s#WI3WR{u9(N z-pOLMg`)UUz3CO*`HBX|Gle@WK(;W9L$b_R7{bdIUc)afHtG=*w=H;RSU8B+6;eB> ze=crC!5Is0;7toYW=u3Ke1wlJ%wf~Q9nms@w=J9%GgCNY;;x01n47?FExaPsC-~ID zv|M;q*n9ZQ!snvv3x(OA0h0=2FVr%<((pZ}C|$nW*6f*`xU=VXLG`~hJ*P)l&rYqW z>eOy#&N(t4!WugbfxnM9ZwY#;()w&$Dw5{0O{tvv{uVy37k5{b4dN%8{Jp zp92$v0s>Nl0s+0V_T0M#i+U#<^-d7#oe<;RhLGTv{g)>9CqxkDUPwPeC~e385i5kl z`GUbO!Y|6tZUg3r5;VCm$j57||`5>AxdZAltTu_yZ~r zVT9`-qU`zuFjNmtszIDl3FK4~S5*pc@%+`m5&Vil%1=T1iEaudA%ytL=4v^C`zf!%(F2*vm64aC)(=-}R~4r!Zd>WHEfb9#pgl#>{3DL( zy(KO^M(2bf%t*4&*hW`NE?5765thLI4hMzftv=%sULtJ-ce{mrh@Nfq^6ib&sXn8` zP`}#C?+k2uc9{9ipk0ljOC80Kn!va^jwyA5xju;{HHCsYgJty&ZmDVb>MZW4Iown8 zoE7itoJ=tz@-6Oe;In3e2Bh;-F0s~pD;fuOn&|JUlOAnCS`e&EN!EEFTS9TiwLU=tl#@c zs*A{|rG3~L-Sux&SCsur$vfJ=J+FpjQntKWq@NN+FAetp9>xQyfq1cvUwq&4Wti#; zVyXa3T|**;n}Pq!0X=K-Cp5p*+s4$c8P1J z?Q-q1S81Rxwx^#~BeY8Wq)cspK*Cgd1a{J8C=0ggz-?tScZ)m=F)tbJ-J}wz;xI?$ JJa^c!{{sB+c&PvY literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport$FixedLengthInputStream.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport$FixedLengthInputStream.class new file mode 100644 index 0000000000000000000000000000000000000000..f8cfdc94d59c5ff05122c66e9561740203feff71 GIT binary patch literal 2111 zcmb7F-%}e^6#j15WMR921(H?@nj*!J6av^{YicV*kYEZ3lnS)fWpe{-!*05}aj3s$ z{86prkMW^C(9yAPzVxLtN*SH0@BSbD8;M5c%7kX<+{(kS-x&qwq>s}ut|o{8Cv*f8Lq^#?-=hINy|xQ>|)8E^IdMNr^-&7 z`^mInuJKuZt;9V)l{KC9q<5`kxV%(MI#<_xznHXapS!kENXpd&xyI~O%jT)c-US9F z?c_K^bCx_)rS%o=&KoNQ^0Z_f(D?Keao>u6&DGaHY)-i)O zbj)H%#~h+6=5<`af{KeeV(8WJCWaW=rJjUzW?aX2Os7yK!*IA{^Nk`meV&VQI~R5G zQBNvPWLwm+gk>E`4CuIo%Q~Jzw~8w|-oo1qrmNyXk_mr!ahJd`v~o{cS7vp2z{QRx3He2@yUz$-cxn_7(jbeT_Nx4KA^7X`sKWA#Ya6n}{PJ$(uNiK1tq0KUsC; zKSfmg{zaayiwgM}SrDMBmbF^LNb>`qPY Yp8wM3MhIKzAHDWRl*b8cwO$3n`q&iyB_iFqJ|ACli=fc18^^CvZmDSv8zZLBqKe3Yb%; zUr}B$f%6&`G+Yo!dXBjv{e{36=r6u)Tr={PljpP+_)ESkjm=4cuF`wH^cLl&VcC|w zCLrbn;-@(APYVoW_dho`a#xPFW9zpXR3zhNp36@O=mOjy%QL&3~G62W8L>_dCT^tYa7*k zI6KGCvTN90&2jys_sPslcD(CaK7nc3)#*Y(VUL%BN=3Q?k=1F=oJz%$q)8OG*>nP% ze(KDYDQmvv*q(-qj903Gw=NLPsstTo)$yc;MF9w$zaLNk`Vte9DtlyWTn!UyI4*GF zKcwLWmYl#f<*XIH$sVr8lp1tAgh4fo={SVLIv&J;jwOs~Sk`d~#4!-6#+H8mg6sH> z=~SDf@F~N^s$s9?DJP0&Isn*O z6&E@zxd#tY@E!4Nq6KgmR3qHU(B5{nw9 zYNuxZ2pqiKR)vKYX4+@kN4k9IE^}R)8}p7oql8r!7;X#al5bU6K0LG#s&~pR&+IBU zo-H&~Zq#aIOyF2UpDm9yIkMZ@EuqHyv0(k9_p?4 zHl2G}j)%?0dx$Fn`L?{=OD@LwaqQlAG2iU+voUI^=7;SfM2a(+9 zHln%AHew%z2aa$|hs$4b{0d2YjV^qHhZ)cCAdk^LN~=6oh93rcs!)VJHBGC^++bN% zW-(Vs$LOuWp-&JWx}N(OvG+ej?k2RAn@FteAem0paX`iE(9@mthwA96qk9KEpD`RA z9c18v+zNLLU6*^19^pR&@Ga|nhXeSY1pI(g_z|=C2^aBmh&s26qKSGDkK>6D^&+wu zAzETYj$Ra_^kZCml0Wuj<0iA5say6CP5J{erBKyz@NUL_A(~(LhxHrz_&uzx@1ASa zZq1%=X1^L%1csa0W7|k`5=)Y(PDNC@S8;Kt+yLT)^9RfQ$#Q?Alj!<|Kt@Dc$`0RM zwg*(faY9nhv%s<)v|4U7vjcG_c|64YMGJRYBM~>_MB~LZJQcpUiam{Im@I;4nJ$9o T@Ca?1ULWQ$%w6NO=t=woIzaNr literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpTransport.class new file mode 100644 index 0000000000000000000000000000000000000000..72a01136c72ee2d9fd213722e94ec972e5872944 GIT binary patch literal 6941 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsEngine.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsEngine.class new file mode 100644 index 0000000000000000000000000000000000000000..a3248280afeb63f277af253ca812246359683d07 GIT binary patch literal 2567 zcma)8ZByJ-6n-x35(wd~l$MpY(qeVrAQfL~yR|I^D(F&h7f|YJ$X=F6NVa*Yte^Y~ z{tCbNq0T5&opJPw&iG6G6^`d7VK~tmcv&ihMrr7Wq7w4{?3+ldtY@Q`I^K1hHCHadR{|a z-CLrcdDGyQS4y-nERQ>uW~zbxnr#|-vlK*BP0gySRnIZ3`e}SC+LudQt8vFoww|{w zi|d|YTgmS`nN+yvG_`G$ulioY_lO49_Di`}1am`wDJb%minig?eiH5qOsI&`Lz+$M^= zc%bu!Xtpb%LV}K%a7uP6S*tN7qRrNUCKRV z7|`P$4CBu-X1Hiry6M;WoKIbF46nItRl<@BZ83Cb1)x&rUbQ`r6WLsVm^_d}WW4T^ z&`nBb$EY)0CHth&46UMgq_;lb<<4B429*N)j!FG*GvBC`$waQ&zN7Q|hEV%(Os+FR zJqpHfPC`||IyR_&&$u-djN+_> zQe?Q41kx5BbwM;cx_C#UP6sz{>&l%?>}DtNsH?}+Q%sBh}aN!+9R}cY^x=2sQ0fZbvy(uku1QrsRF4->WGqLlnbT&ML)H_Vp zi#t2w#(&J$Y=_)NVuLFpsex->^gW+am8&7vR9EkYQe@}9o^hq9} z?=Qg6CB#mv9$M3M(EdE_zJWx4z*N3aoX(^&=}gZNSU!{f1B03LA-aA;_qRx~ACdZ= z%(^g6&p~w4Gm8P_XfX1~&~7P&!3&t69RcD3E>bA5qER7Fv6{r?z;}xLrjQEGUcyzR zgVoD;h3I8zog&X1J!v#)C5WyNg1{Kb7eZFVC|@{2`XsGs^kW9YPy<>bPjYI}8i5E$ zUrrP;9YNoqUtyIl{EnXQXc1;93I)u@VA3s^G=)$Dm}^wxkYSO2g-2KSNsQ|Oh7!Jw zFc=}f7I_LJ;hE0=fYg%{1WGaIV*)9>jyEFbuc>6B9kb*t9iq2f_!H7o^p$BZ|Ac;q zm0zH26%R2`e2T$BXf||&;dZ2RK?Clf7kBAjuQ{sT0?}LyB2R|s5$#@T$(z(fM*DGG O$6Hh^`aA}lZ~hDM_o~JK literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..b308de57b1ae02a8e83101f60cb8c48a74e2f737 GIT binary patch literal 285 zcmbV{&kg}W4936uw=9XhyEr(TxQVL}5+WfUV64en#?0E8^>7Xzz(a|yvy(P$^Civi zYhUlj6Tk?a06~C|5bkV|$7-HxMd&TO&)j~ynp$I2>{Dx&*Gv!3@-7M8nTfS^sY%w# zpX@O}n=py(Rk&Lrb5&%*UQSF9sqrc|Qj4$p4IPXKAas`OluxyEPB}tUS_v&pA~uIJ ipFkM@>k##sU*UJlsB(f;4RxM1G`P38Lf)ZLMa>U>x=?%o literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl$HttpUrlConnectionDelegate.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl$HttpUrlConnectionDelegate.class new file mode 100644 index 0000000000000000000000000000000000000000..3d8d0c33497f9f9dbff6c7cff11e3e9477ffa560 GIT binary patch literal 1894 zcmcgs+fEZv6kTU%nNmims0fIPShbYPfS@2Hz7&lljV9&t;EN9RgpN#S>U3)QD}I6T zO%pGP4@O`8DC0WQN((K?L=#_T@3Uv`b@tkq^Yho&Zvd9CoR!yKCV~xrN3kCJG6`xyprYYS-!2#En`fP6&P0_yS~$=u_+ySUAKT1jVM(~pLz-F)mQf&fuZA!S;kVxOkld_wa3^Cj2*}zEXPqdcD%e*DwD;P%uE|Q zOr*1EOkk9;+p<*mWf)PEwW{aV7&+A$*~25J_)S2 z0t*q_-1O&W%tcH14}OY^bYg`jI#=k}Kfb&k+|E2E{&7v`r}+5zgW~rP3~7l>SP)h%x@< zTZxGlzDdc=M?Cux+IuQZ;C^KkG6Xc54lO|L1tw`x$>k|k@Hm5GKM;R|l+r$<|2y=z zh>4Scb_d{i6ObtzxY`1IO0IDNCbF}Nsc188CiEKH5TL1t6 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..aa17ef97ae175f749f7788cb9d50fd3048528f07 GIT binary patch literal 10545 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 E1~tXlF8}}l literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/Policy.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/Policy.class new file mode 100644 index 0000000000000000000000000000000000000000..1c4d86e74069e28a220855e7b71f9e34817dbbef GIT binary patch literal 428 zcmYjN!A`6tP-v!6~|;cNTr*8{anoTPXisxhnFR%Rs;k}{I5W* m%*Ub(Fdn1gu!@?)6Vx3x_IeYiZf@=QGqibwz&XDqbbbIx*lc6~ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RawHeaders$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RawHeaders$1.class new file mode 100644 index 0000000000000000000000000000000000000000..6782fae1600b268022656757f31c945ccbeaaba1 GIT binary patch literal 1025 zcmb7@OK;Oa5Xb-PIB}9XG_<9>LxDo`uaK{Mtu~YP>hRXm3 zxno(n(=xg1>g1_*NA{WOzVo@G`!m&kJN3MoYFM7`Slm>@U7vq=t@E+&xVyDFgG4uG z6wa_$?4I)XTs65hQ8mvotV#W%r_^C!JSgl!FdYn6Fh|2vedH}-Vo!h(K311G@mX+E zW5{U6#NwVG)Ye$Yw#4*3!&Fm=l@YXb{k#MFfd=xlt&wTF zB>0W)P3^ISl8g+pGRmmP*uZs${Hol*zsazFxsES^A|(u4A$vs%gK`-(!*=UHYoBy_ zTDzxpjyr?)$x;7hyH5vE^H%tEROwAh^oY{*XcII@G40mKQfa04g=F~~*k>{X$TX)y z=M&_}mZJb%!ByJPcf=;m!DWwN0j^L{J|UTySAHWY%oUo&`48oy;^R92 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RawHeaders.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RawHeaders.class new file mode 100644 index 0000000000000000000000000000000000000000..49344dcdc9971417ca9984ac5c7e39a6a5927603 GIT binary patch literal 11676 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 E0p;){BLDyZ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RequestHeaders$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/RequestHeaders$1.class new file mode 100644 index 0000000000000000000000000000000000000000..976c564c33d1df12df606ccda0305b55ebc6d68c GIT binary patch literal 1577 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 C;0>Mt literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/SpdyTransport.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/SpdyTransport.class new file mode 100644 index 0000000000000000000000000000000000000000..7b6a45b6f9caa9970bb3f24fff91e74fca44039d GIT binary patch literal 5184 zcmbtYiGLJl8Ga_&WH*x`z%~h#Xo-}zIoUuhwgM>-IYO5th7ctcb+S7oLpC$Z>?|Sm zs8?;(*0Ua1k9yVvYpJl%qOB*|df)f$-=RM5%FO`iSd zlTQKIihrmWz+4j&$jD{B2^Q>TWO1tDU&S98a#ZBts+7o!*l86DIHPi6Q6}yZk=Lkr zEnXMH>tncE6udzO-zYL~lFOUr^(`vy!CO__i~D5kZSwSX74N|PGW&pvcj8^5`rT2y zM@1**RJ<4OlaU8S^!>8v15tcX#f|t-3}@y3;V2#wiI1r0!AG0$F??KJACBS^QG7Cr zPbpAmT{pYWnlUXy!Iosoo=@aX<#or%XA}0EOeRdrH5^ONB)qqSf&2~yExBxZamcnT zBjuX5rC{6g8bmyCq+$)VH0E5#(C2H~4^|)XkU!D!e{H>uW=^Qy^^Zl#Qjk>)^%7bJ~>_F!!VhdjwLMTc4b+5*Y273SxNop(~k ze$y)!6}x?l>}d_RV!wuMxLLysaZ41R(ePP362<2&uWZ~$M7;+%#r;ZY6yM0Pt~ z6vdY{JcivG&dbQ-_=<)LxEMu2!zEl+5IZpdZ0{Z_h$G!p{$ zJN#b3U~M%=tvSnHu>ATcZ7h@{4S&ENMe(1a__Kz;;IA6~hQBLF)Ye;(PHxXKBBRqM z*%%e{)>aZ!f0mC@l^-4r;8W07TSvJy6P>J`F;i?CJu9dIW1cLxZdYw1zAUNEUA}*b zw!>z^##7@Q;5EHsy)5^Sf!fw9*AVQS;a2s%NY^2$?#tulaYqtYDp0E#PIz}SKxsJa zT-7F3N(M!JU}Z%;sLoQWQ=#)x=aSh89Xk|Uw-hR63Gzi8BApMLmhDWIS}^l4Od4>G zZI(clP7meA+cQ~U)YMw?sZ#gyne(X=0Lnb+>9l0BI#0)oafFro&i(%* zLNEf%?y<(TN2>aBycAZrLod(mfR5q3Hd)3(iJp6l!IV`_P1QI~1Uh{kOhscVWAcE= z6feoT(K%t!kS9aw&ZT%4mSM7)%yAwzCd_%mmQLBi?N~9;TB>E0d#fRpv2${6_7qed zl;S5Gd%haf-OmA_M)*}cVLszPjfUl%C#;sO#ywi2C#1f*riZ5#ezDxb~NzXg;nTA8$aVa(N9mdcz(1~hI)&Btind@!Cu-P;%J2T zm++5=Mc)sl4UPN-9uON>5jiiW3s_b3pupPgKdvrdP2^$3;%gs4Lp*-iAEn>dC>ZJW z-&*@GqpgpZcK>}{0qYC6R$dC&usssl-q6FB`rZOM+9GWY1w8K}nmHnWMB(`bTz5|a z8_QsCgGT4JAMu;&h8`}X@)(+x4Q`M{RCK&G3WV;F}R{4R{)4kVd`G(kL!5rQ+re~*mvsi6X_F}&0Vi<;~BOU7J5=dnw8!P9*9 z6VgcC;3~20Cm>d|E&LkC5zdDbFi}c?$2(c;!N4RJu&Err>X|zLmClQ5%`?+nR2^1$ z6qA${W$`-TM*8Dj1$6fdwdy@;ZSau0 zgI*^|ufwF*C<#7>UZNl_^!Un)F2p$ZGQ6B_ts)7J(ak!J#4yFo)Z-PD7ngmh<5d{E z60a({e2|C>uB}(lBi_;NUXN0j&{rnCkMYqE#;pOyt#~!`D*e+)aYP_lpmu?zqvI^r zi~g(J-n>1I{sOi{&eflboa3~gN*{nJF1QoT455vbS%+y{3nK(TM_{^x1R9|ss;9&W RFOUvWX_f#eFg?8|{|zoU%Pjx^ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/Transport.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/http/Transport.class new file mode 100644 index 0000000000000000000000000000000000000000..fdd63f21d1d4488a23cff7f0ef8595b7970787cb GIT binary patch literal 671 zcma)4O;5r=5S>M&iijY7{e%(|HXc0TNu!a3ganKSZc7=UP_|`1RQ{R=e}F&AI0dOt zP4u$Oyw2=<^WMIHyuJaz1)Mr?xWKO`Gtv|4$H=0ORm z2dI|&GN`#rBP1GrBfQbdr~0=+4Y}@5VJarnWOb~c0e8EF59?m`iWi#3#8OyeCFlbEux?&1>O zbFpE<9zJvN5f)uEG3DYe$^xq=>wjDe0=G{tu)a0Wu^;IFX)18;U{E&?h&_6MPd;cw zt0M-$5Ilcup@%x`u`^zgU}rOxZ(VJBnRJCxi!!ssWV(DW(wVNAz(VYU(j^%h?lf;ILD{MH*gU)C*VA-O12M0yiJc8W=vSuSTneg?jFaxn8g_87`3=| zk$=w5@T}h%%X7u6zM7r;6}iej#wtI-`U4JM`RB;zUKqbRJGYO*l2x>FKVY(A{fs=f z+FY#87Oj1Z7p)g8leJmHDcbL|%@1fTu$2$l#3Fwsejv;I0#>kuDwgT3p_W3qnYD2M z#lt)+7$_dAETm98)>$BwMFP4+%lZ!}-hv^hCi6_@^uK8Sggy3SiioXF95$Nqd7XuB zq)oV4+OUaH#!75EQ|B??ruYnLah}6^X~;;)`W`k9Jas771r)gP7I|2vAa^KwgU75; RqScY(W?pk#g?Twt{{bDib1n@}+L-QxLNfqA3~}7Q7)$$-s!C+yUggN|f+ zIi5<+=ACTDiZ5u0ETx^L#YH=lwPy3nR>n!%X$|e}a6XyNFFBTmo>o7e;;PwPK9RB= zYnJ|#>8zDW$6xyIo=e%+@(DYg&AbY_h+_9 zN~ucll%-u%TN{)(m$}p9JT+S}-HqiDm?~CUI=n-Y@x^Ugt?K65)Q;*n%^MVQYMb?9 zX|61r)ba9ejmj2U;FF3P~=FoqEg zV?@kxF(<@~iiwFiDP~N}xR_I7PK%ikb4JWrM49xf(>K+51f|;0FvH$qqI{ty zv>)Ml0q-OBcpqu~YAnL}myl@9pMXcPZ4v0vXYjp%E(<)bEtn+}cBjF@oEqoea@Gvn z>+sSwus1r={}le{z!L7s-^6e0ejEHHf_ zsYFXlWP24S!rf7k?!y(b9(+I{DJ-;vd`U*U4?aUEHS+v|cY2`zTl9?#jGxzg^&epL zeFJ~5{^$#@_VAxSwO1m$mFpQqDER;d9b;`Iq0@91q3pCuO~)bFOqFjO_G6K0co@DP zS6fLABEuHQId7d(;LRz`GyG+yG|!Z-yi-cqw@xYe=9JP*$!1DvrgZfkQZlfFWq0GW zhpZ?+?b^@KbKPxTugCio;m2rK{SKX<>UXNX>C=54)$daMZoeLI`w`XO70^w?C3+OG z+tAIROYBj^UeoX6Pxn=LQ<6w_}ShR0nrposlu(Da*aE_Far2h9-Ixy&KO z95&lzo$`D{F-OfXgS*Tz#k^;>d(4o_44NIkQnRiB2cyYog1^`J0G1xj>Wu zSaL=adz_p}s+T}+AA#fmA=tzL0`K}ELR%9@2;nA<5!#y=bRI*K+vi^YX>_vP1Cw{| zAo}?94)C}i?Q1@4-|?OPg)j8)e4GE^tNa%?-qX5w*YF|zc#!)S D>~aJVcEKtL2~{n%6jX@_7Q@QTSgG5IJ=mV6{WTVR z03U_8 z4aM_M487g6iK>IP#%FlKkR2&mD(4yA9)x;}pZ^KW2S>(O@Oblv8)wOowm&tCI7J=@_7w*bTql2X#+ZhAD=E4u~ql~W; zF>F~hFYosDyx05v^Z5nf3PX-ljvhy!}t*eQXE5&d#y3g!N`1e{mRhPoPy;fBz3R5X(q!zx+ zH=^-AG|cnA4Q|KJ1b(!&%haUMMC$FhE|>B{GFlIt4ylW&>rhQdIYM_=A@_0c;sg=Zgzkd# HAc}thUEOyK literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/FrameWriter.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/FrameWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..b7cf34917c26b629f4ef4f31592d30b6a29ddab0 GIT binary patch literal 955 zcma)4U2oGc6g}SBrY#$EYy-ykx3UMY_B@0H(ZkuYnmw7g0*o=p@^4nGXQn_dxoH>S#xK=E#z?W)utn+8~ zcPK3}6Yjni!pb7&=F8aooGb06)gt3APiK7JT4VQ2DucB~D!gEbsQu%&;hw^&-!IQ? zC%va@piX)GAJT)r^trM&CTD2mB*4%j*`V1PnKx5GH@PxZIyKV|IdwoYX~y$-cVG&e z$ODxT*gLRdB0pJ0240p!rP=-4;e{lU2)htwdUSG1o5ipeAZ7SoW}Fl!Wu^5qtbcUA zXe|bYC3=@>O;;P_1x@;E(O-kU5h3jg(m|JU&N;Y3>?N!acNJG_BG)L=!&*(`Iz`s8 nu~2anH!8@@1>_dC7LePOKJVb}0_R?()_pv<$f5JY;O5aE%_P;y literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/HeadersMode.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/HeadersMode.class new file mode 100644 index 0000000000000000000000000000000000000000..776cb06da122bd1e55661143b30d78cf7d3b76bc GIT binary patch literal 1608 zcmb7EZBNrs6n^g3t=%XvwgG}DiYOZh1q9!Qgau|G884xeWcq=WQJ~m$*mWc({vGv; z9~2Wc8V#TQQO0vGbxa)})+P7syglc+=bZNEudhD*f$?(k!V zduI7@mml{ObVW(tSCCMURM5?>4`e)K=+rlsirac|ZCfvF=CZ2{TE0{%YtJ1 zTIKnH=N)O57Hvj`&iR4e{}0fz9Lhb59q~QGvRC$qt7(+8J5|&1gzG6oqS3YCnrA-W>d){` zM)EAyx7LG|xsvTu%Qg_tIkoa!i*1<~t5T`CCG)YxyB=#;qY2)16+L{BdsSpG$1vW~ zBB~g`BNf*%q#}X1iX=a}_#tfFh%20jE};(${iF?%=Oc~2)-wc;WC|J;fquJ0IvA)vj_-lTLRMP7lckB@r1x%30KLYo`qo$*My%sLs7is z6oT{vB9OrbkoG!Ax+%zoOh%f5j5Y<4FJhuK0Z}jp-XPxLSF{xT zDSU%ej7Ni?(e@D$p{SBjWTCW&grW$gBP^6o`8y>AsSkQlqR#5Y5H(gWhEM1V{t=9i h>uf!G5TgGHwA23gqnobKgBcoEz#rFbjFUfriQiciN7MiS literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Hpack$HeaderEntry.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Hpack$HeaderEntry.class new file mode 100644 index 0000000000000000000000000000000000000000..9f8e820de07aa5a11d3482d20ce9e8c78fc86d7d GIT binary patch literal 929 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Hpack$Writer.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Hpack$Writer.class new file mode 100644 index 0000000000000000000000000000000000000000..6cf6c3ea63686adbc578ed256277b9cbb8276ce1 GIT binary patch literal 1681 zcmb7F-%}e^6#nieVMEx40EJ2t5S2=rP=d9sR06HRBC7#(sQ9BZ$|kH~OW35FU0NKc z#Tow*`_dWTI-@xCq2rq~zWFEkkBHyBfsish=wy<6&bjxV^L^hr7ykU`w-*53!Y47D z!_{sWxYmQ~cqfJ#+>qA0I%Z=G7owPpp$qfUxhc1A=_u-05D3)+Utp+o&)T)}PCdUG z_>I6{^F7XmJQM2p|aC8^3w@b?~EZh%T|*t!ez&&1U>3b z3yQ$tQLRpVGD~brNwz{IWUtf+be>_2@}4i7qTMa>_*y;iD)yoyTN_h7n38u4Byih6 z9KAXg4UFIe9ZLpGd}!b!lql`#%myZLnb|+Rvv_&Nz%o`0yom{UXI00?0#pBQ23{($ zTE1sjDAvI7NSmweK5*VMl6hS1wR^3?oQ?CxS2|w-aVj+_Zbpe8s@hCHNT)-xR#i4V z%H3j1wV|_gmr6!5cZ(9n#DAoTF}~Y#eCuqJ)R|V8-vs(p1XzT|4-m`#3X#qI0__<+ z4Fmj*BgBiJBP_l^xA+q085?Sy#vopy$9pO(9|(q#?5EozLg4n=CVc{D6 zSy54lvaF@y22x0K?Zy?(QCcELp^dVDQM^iwV~iSH<=!Y>qxCxNFxNLQPD{f@+8iia zlF1*;6X9y6(oYbV1V&Q(WbjOxX=$d?n}t*#_J71^D)IQy^|0I;3^Ss36Z&_Br-y&b zU`k$8MWnb_2n3>vh}c4}aF7r?ND3FD;yx*Q$cZLqgpWB9;Fj3Ml6au#UL~L$!DUEN zifpz?nz+Q6BxfS4#E@1_iE%^Z?z<*~u4uI1C+d8i;rD06iyo z`(-up2)cNTKCzEs@x8(`*2>UEk;D}8M4_{J)BG2sbx5p{wG{bnT;LkxDFg3uq@w=< DB3NU? literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Hpack.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Hpack.class new file mode 100644 index 0000000000000000000000000000000000000000..803c1e8da1dc8ed0ec9e44c936e1c616ce088a94 GIT binary patch literal 3116 zcmbW3X>%Jz5Qg8iWNR!-KI9zEMK}^-hbVFqauAyY+fi(RaDpwIm;hqDT1y*CyUOm$ zM-mA44dK4;8^Tc(A3{OFSE~3i`~;wPMk6VPqFj8@&ePjH+uiR@uYUjYr(Xf=!gpZ| zV>X05LxI5zqY0-O<`{|$B?gPZW+*e9VQ?5+29Ke_Fwd~Su*k5)aF*d5!+D1L86IG` z!0;f$LktfyJi_oO!($AOGd#iYB*Rk-Plxdgo^8bto@02P;UdEe3@Cnp&MhUz%3Pn@(oprlA=;@Na^d^9sg zZ3+INp%(L>d)H%{dq|%_(=xq78Unq2QyPLJc8==pNSl^1UMbBOPKM7E$r4N3IxkLf z$Mm^s40;9A)zG)nZczPfP%l=W7@o8%j&2+^{r$tDT|0dhBDfp(XxQ^VTC5>-(A5h@ ziFOS7n)rKN($MU$DbwbI1>5yBz+aZRSD-g9;RlrruVCk>3!}*lHHGWCQ6|53xrplp z?zjdSI;sZ4((RmS;atYeo*0zWP8=@by9rDa=&V*i#yg-}#CEi2aY^dlv{7@xJB z1@7dipWS80UR;VVPrkZEVBX{*d>z3z_%?z`WQ05(ohb?p?C$TUU(vCk;c;qZh!Qm& zgKkD?f_SywQ3=$vdB0C#Qh~Z5`x~6+{w&$xYvQ`9NpaD-I5jhGQYWKT#Y9ei%Bn{> z(=FSsDO=g8taV{)rn<6q6CDN_7*&DQnuGLq&ry$yHIG=mN2HZWfz(}Jd8(8oXmbpj zh;cqE2IxB1b4=Zfd$b*;=Xi0~&?_`usm?B8q!%XMkmSO`f@r_mI)W2^pSP{>@X+KF zgU_!qact(acu#h&FnEg^`zsDmAA@bZa-fRGPEyHMe&C-Le;~>9#9SV79KJ*fws6-U z(KJhYPc;O|><9Xmjp_mP)7NU4J{$}^Na0pG`?nD_Ax(UH1CJ9QYvAL=cQo(>F}=hT zf2W9_BBo|v!6zI1r|JG(4Sb58+2qeQiny0{*h5zuMQGlB8QS+^%Pjr+{|SI|2;w~M zqg6yYfn$bv3j zNKjiWB8Ul!Ry{kVYr8_}+o4c8cPeZZv0Vzo0%Ho>1a>Qo2wbHwDsZ*Jc7baYb_iUn zuv1`*I zh0-~$P|CPdp_DP9P|Db^P|8@XW4cqyxJ%uYGVWF=Wvr?CuQKjY&Qiu36-pWRDwHzr zQz&KJuTaW(K%tcJCWTVQg9@dL0}7>#g9@dLH!GAf9#SY}JSLjV8( literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Http20Draft06$Reader.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Http20Draft06$Reader.class new file mode 100644 index 0000000000000000000000000000000000000000..ec6810b267879515983058360e003a0034f41333 GIT binary patch literal 7293 zcmbVR3w%^png5@8-J9V8A!UGIVh04tqmoeDNP!>$0!&RwoP=gWQM}Atl4&P1)0qhY zb{E&Rx^CT7>$>hzt=0NKD?VB!ylU&KcDGhtYkjm@*RJcXin_b%s;g_`|GTfbfhb^p zzkBAKbI<+0@Bh8;&7;qrc@V%FwKR?f9My1V93i}|4k^4{hPyP}9Y+lBl*PN^xCif+ z1Mi9By?CF7V{sTbs^k6g`vKX!S7sm7a6HZjJ|t&9tl=Z!>1iMgOe6ft>FH^?_fZ+{ zli_|DJ|@G*WjG3JosW~w5X&s-@@mZNZ ztmAWWJc57H@z1h;RLAFaJQl|n@I@V8lC6Ky@ns#4YxqhW*WqXwwoupM3Ay=I9beP& zb(wxc$CGh9g>UNkRvZbOmCdJR_;wusith-%XEgkqhVLqbas`FPzMIVhW=F2rvDK`a zsX}R@I#?}R=J2}ZR7%-H9Xo{33WtDj*^n#bsv9Xvi!V!1j@_*{ zDnzyvvzEgAzFfiDIWfM^Di4|a^4w|YD`w36jb=F~Yj-nJ9m`RewU;6c<-59bYuVgi z?d+-vm6%l&g@sg2c1w|%Gu2$Nu)|eHxJ87l&s=aLbkk;qc<;fCRg&`*s;*!itZplt z6z`Dp(uySiIfw#jzVYGv^a)r_L8-<@Bl%P>CWIEuppDW9B#SJ9hw#wyVSv)u;(NyOz z6<%-&7U}h#CR3Z!pjE9>3aTM`K=dJ@Oh76p7Vz&~bqSjYa}^S` z0S=In=+-=xFPd38fj6ZaM9WqwPj$!T(e1^aNs|kMslY`pDz7h=%v&cc(Nmx6H1%?P zI9JFPCwG;yW|ge2n6#IJxx-XZrfiMdX=k2Q$ZpFQCmCbDJYI4%7Bn|vG{>Q*i z@iQ5IPK(-LY=Vx44ZI0=82DfOg6i^+26S!U5K0D$G8~rSPi1(e46l*lwKCi;!{4H$ zu&PFXSD`XdDizC=vA<-MO-Z2v2Z#*yZ|xTa{8C}*(8xgV-W|O?TYJ-kNiPp2yStN} z!unSR{ttT${2IT}@c#yWi)Rf?GiI>besD|w&Y{%KT|Gmo{+-EeE?ZbtO^%rdtmL-7 zp6z>kcW(7aD=fe80iRulsdm)L8cL~rP&ysj#6U zDys0Dndf|Jj_?%~Q@GMTk{%q|J2;f??YZH6Vji==i5X-xr5Q?BbqcNLQ<`8wa{a(g zO!S4UB~ltHuI6}n2YZL8pzVV$Cp|H}X;U04G zRFe6~wEezXo+xCPoT!F{YL1~2YLTWE8)}JaH1Jl5>aL5UnvoIQ?t)4G;tvMuyu!7Y zb>8a>6qd~1P)R{ub#an*n?}E?5s@T*L1)%+36z3)kxA3cWSDwabav7;A}y`bBGpMv z*fx=uauRL1X|vr<*@?g|@jd0Td5CTnv)EbYInj8Ar`Y+#%u}M{)OWgkI2B$aPF*G!=_v+4Crs}wa4j@2+I?%3gz`u%;z-Sx<{X!nVz06y1j2*|Pf*NO<{i zy{*!c-Ic|tQk%rGKL}tKn`DK#m0NP9&4<$TT>IhQ^R{(;>-CJOQLmYE`ZBLg6PfMT zu|N;t#ZYX2u{>_lnXj8A7-ngrf(CVHtVbu`pBq?{ujjjWgS16_)o+l_$o^%I!{2$l z1~J4_yEv;ND(~rde%nc?wzCM0w4X%y1R`xsClKXEY^3euh%}vqb^`i+JQ>1`92fC9 zkWYkM>d7ZTE-T4rn7c`bBK`y;T#+`<>?S{%i7X+`Z^9n_iUhCYZ-~E}$R~Ofk^4@e z?!gE2K4IHFg?KyHr!ePEEISKhG@>#j$ua4KXyf*Xd z=e37dj@JQRujch8UUK%Xw)R9U5lLt#(HJ>iTPzJOo)cU&1sBc1#dCv;D}#$4Wu(1B5c%OQ_j zFv;-{+s4~aVtZP_9dxw6oH6d<1`m$LS7F;Pw2} z@;7(}Z?w&|hiWq@N0vOqRnPg3bq@QEgCaWo|a(-IY#X?_BOZ3&IEx@r9!HF^iX=}mAZVKC)eamux#?1^ z6KgwmictDHNogmoILTduR(JRxB(GZFhU8Vru_0c?vyup!XQ;7VOd`5(K8+VdQOg?h zZ094lD-Hn9} zt0T-{BjM&#=opkl=D1v^XHL&gqKT+DK&+j4A$A&T!U5TxjQ2^p|EHLRKaJJ+EM5Fz zX1veYICePvd>os69GiR`n|vIbTpX)eJH(h#(wbu%c&4iP8tNi?(nU1vAi8>1L@%5L z(J5TBF4h=(1c`=gore-pPY(pzNT6Lopv&n+z@r5Ec>;ZmK)*oYzDQsA5{uB6>GO{V z01x|shkd}qKHy;=@URcKm3helyqx}jygDe9;Avk1{6L zdXUfJI+m_=>!RVVSR&SZ53cges(BNg0luCA-WW~Pg%eCA8*Yo~$EKfX4>v|nqdTaD z)iek2H7vo`u?pW{*?*E>wVz^H`6f&4(=2=6W@&j6`|urNe8$$ue#*NUOKpQ{JhgzC zS7I{F{a0~ThZizG{v~G;GkITgd0%sRUvrY-CCAD+$)XWTuz^|pHfkm4^87l%IF%wl z$V(aqRg1TnU1Yvz3wMok(`TxDrpjlke5T4}8j>#`t_MCv3gQ}R8bpF>5{{xsCUJJNkVH+uy9M1ZHfe1iIIjaC$aS*X3j?aG5}n~$Z<$I|9wY4fqPxmfDhjyj38p5}gojis69e&c!O zzFj^Hx(IrRKq{kckT$lz+r=i_a2hl_npE5t%IR~Qi<{9 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Http20Draft06$Writer.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Http20Draft06$Writer.class new file mode 100644 index 0000000000000000000000000000000000000000..1f537dcdc99ef81e8a9084be5bc1ee81171d5ddf GIT binary patch literal 4656 zcmb7I`F9i775<*Kk>mj!J7TjPAR$2*jEvhjG-e6LfZVv4VwPY+!dM#H141K4Bf!B0 zn$k7h(+#?$Nf+85b55~)nsbuh`&0W5m45e)Jd(FS;GlWSefNIvyWhPthkyU?U!MZl zi@&Gw0z3oNG$Qa*cpf$Rxo+S_8VPtZxoO~?G*ZF#Eis%;;~TgwqdNxfrm+rQnugz$ zBkzjow`6oL3Os%+R^N`^c`Ty@zLUgv#r}I@|9#o}K^pJjp8WhUN^@Ghhabttj}839 zz)ubQOd;yle1**;m#yno&T(@?mT!&L{7TIq^F7bgrGF`C>R|ad7 zleVX@B|JAc;UMR~33k3hvch^;*sH>{=z~ zUYYj&O3o?sP}wTws+HnQE-!(%2Mz?)ey8mC2Z=o!f>;!LeCJt(*b%pAE36xF%Jzxc z)d|}>ZB3N8(l+82tkPM_b7Wp$jQP_J(d>H~Gz8e!JLFlDes6yR)%umOD8wgAwdyqa z&I+vb(VGRk;yZ4+YT)Mztp%5S6l5W9TScKNRh=mZDNxvy9UmX&pTK#|cS^Ytr|J)g zs}?5k7^$dE+eJEd%8f~~s#7@3bv4W@lWe!(SiW5h9Lq+s;yEs}GefSbC6`%VTehy+ zXRT7r9xS>r5gF5A@frCt5YRs7`TYk-BCVE!B z+=?gV!buWy%C3}%IFlV;k&~Uv*H?9COl!iK_GhyzI?FCwUe(un#$C}z%qK&lTq+=wx;xp;IYA*W}A;;?G8n1E`c7KsWgjsgo z3Lh25BqU*1u*JPVFUg8EQ*y21UeSFp?4#L~d-#S$IkmDK`Nv(isXWXZPPypbI8)*M znZS59aJa5$mwfA--Wzk?k)1-xt@4>3b8B9~KIZ5qlW*=4d!)yj$YGzt#?|_*?7wf~ zMZ9EU2eJxX3zjQ(SQ9(ZZQvIQd!8(Z<_>CN7xtKV1^W#A(!{UuYZJf0eT5x5o-Wuk zDI_9yvExd)=7q}fB z4eur0HfUOW8!mdGh>~_ZIf7=HdVdPb=6g{(R-s^5tJ`~fdr4n*r&L({hP*jNctP1w z$-2l)y&k+PSX}LO$ctYMv8t9PUpeglNqu5isxp? zZA46MLaW-0jOxHv)rp+y!k4(eHSmuw<7LhmiTL^%T}Fa1f^AYSdaf!)K(a3oAzr4c6GmB;h7j$UZuBz(A!a-5pV7E7Jq=)$Kv&$STl#U4aaK*pxTb4 zdJ%2vr6%X?D>&be1GE>YA0mz{D9$6MVvMl&X z^1vP&1Xpq~N#d+Xdk$@Uv}~gA+GG9kVCmWZgwbzw+(#;7#P0SRU6Buv&KRvpjzvzH zL|f)|YwOKS{24sH-I~04H)F`??i|+3erMZ;+Z@WVwKDGt=HgtYbJ*BWN+0tFH9(E; zXDuB-yE=qU^%}OQ!`P_?@v=ICGinHz)KOH_G2Bweo76NL@-iEyXEsdFEJQg%^sG)) z4DE1mN~@_8moTQ)v;`M&nxkeliG7|tEluMYrtvJ!kxwZHNwj!RODVK%n#bnPI1742 zLUN>DZ^~gh#G2L!C5LIef%81kh@<$9yHNLkj#?MBwot7-(VkD|&>_SH0Rp{_BCSp~ z>9r*c(h?HV5)#rv=Wh~nBiuH5rPjm!r!I_qv_BDT&c7rr6R+ny@wqt{)1C~i=g`@} z`W(rHI*q70gM>QEM4v;idIJOMJdUgJriA80{P_@nKE$7|;}`1RV#4DHY`m!^;c)J%Y0Z%|xC3mk6Z)RKLC98xaxPGE5tKCx5lU-P3p|Q7+!2At z_#(Wdxr{GTKrwuI^zppNGP%&(L$w8RzM@gA{u;6wGbjydzLFi)xOCv+T9a5+2w!2U z{w`3MCe(-=Wvxo}HYf3NSbK+PA+@(Gz;zuUXq(LeuF#p>O)V?AZ7AVt9rvnkZ>{2X zp&Kg_FSr|Mm3)@g-7a~@Z)>m;l<{r$zdN5xZiLB}(!YitKHE4-VFtU|$)D$c^z6pQ F{{tB{sEhyr literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Http20Draft06.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Http20Draft06.class new file mode 100644 index 0000000000000000000000000000000000000000..5b5e66e6760cf5602ab838a198c4357be72c2d92 GIT binary patch literal 2075 zcmbVNTXWk)6#mwi*iq~>H8f2_fD}ToQyRG`ghE2VvE>VOEMv(rPGLNXEm9RnGO`Tx z7x7AAhRo0zc;`nkoL$+D%)Nct)pz!s?_78F+wVXB0^kllpGOiE35)nRhWir2sK#(4 zA&OcYY8-V5pP&(g7K1KffonBmIF6ykFxPS|&vY3Q727u5eBT%j%^}GfrqSc_t9i9n zQ}TL6t#!&uuAnp+LJtlZ=Jj@6=@fE$j)7Gel6l7-dWP*C8~u?PrpQ37Ldmz&xQvma zkkuO%wNcUATo_`wB7_Z1?`V2M$sKWVc%rK*x?ZW31VMyC@(G$+xl?bbM-@%s+R;f! zbyDSmIfezHSyFSYoNyFlNC{D^QY)yfPP0z&3+wp_Eu~AonmL{@XOSqjVl`LlD7C^k zHio6CWSkmBDn!Ao;uMfCRBI)MYg3zIm0WW_4Yf*@-nVSaJ75T>Gsg^(ywfwuXVtRJ z+UWe$bamsjPm)yC=^FiG!?idb3nSh`i@J5E+I7z5;a4NWHAe&4`SPLX4P?uv&e}#_ z9u9hs0cdr&l7;pL;-}I5jj|%Mli$2AQ|1RIUH_e zvstQjI>RS9zE5%aJz!Mm&8cnE9*zbB$MwvfVt1XMWuGbEcFlojIX1bHG-u>?&7vjR zGgIGfUd{wwz>5jGpgRn^&)A?1zoOjw)90}E%fYSN3@bF1>s#w(U9ZbK+u5X)l(Zwh zGDMqt@%FtKP7-*4&lol)WAJaO6QfY;8}^x;qxZt)1yNkrq4z?5#zg5dU6QG%kIXK$ zFZ16d;v(=_x^X!>v$IQ=Y4!4KW)4pHO$+#?d8gjeB%GPv;bV_KfXic3k)(gVN7I5V zy|s(=quqXVHfWbVz`I*XypWDMChMI7Ecjw-&(sstWm)__h;6_e_;IxxghIO9EZq{S=Yn~5cvU& z^RYmbHxWl+T9&qm2e_V!rQ$zf{ztIykhuR83+)Reetj}_krajEsV>tG8`N0|X_~Q3 knlj$i%(QrmM6aMoIw6$ATE9o){;*(uSVr4O3; z;1BRe8P9GBeKDc(Fnca@zVFPr?C(E6e*tKq9-xAiS=4YVz-`>|ao5K^ANLumuas8q zHAA_+-eK^zO;0k+x0RNAqd`~NL(xsiv(Pq)NISx++&*)9uCFo%FoZ3wrQJ?NmPzt7 z+ld+Q?9)hCIT~{FvG3fFEA6D!BIVhz_l37K#VCCoJ1fQDz0kc>+OXfoJ z>QfNK#5N{r<|S0Kf{ zM;WJ>c=BMl%$s>Tc{^`sKfm5S0MxLrV>=6moeVVW>L}~jV;~}LDJ6oY%fnEF4CTJr zy0*=s)ou1VR`+sf5Blas$7VQdJKoF)ALcv|bKmgp@1n>zq>4nKxNC&|_{p#o^++|b zqd@T46<1?d1a$^I5RQ-w!B9K;hm1{HKN9uh8-}d;=mLl}bkE49TOo zL2G(r(k`^665aW1B!U4Sxx{2`Zyq?JCF7#{=X57izTo6;MRSL>JgO+rj{+j1WM2e;~x|AK>8cc5t>~9 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader$1.class new file mode 100644 index 0000000000000000000000000000000000000000..7f86c59108a2af3c909ba429c6806de8d9945eea GIT binary patch literal 1495 zcmbVMTTc@~6#k~&URV}d!A4N3f~}TvS+13vsI8bZDQHCTfv4$qN>{eKbuUDo{X4#x z2sS?W1N>3OGo`^Mf)CwfXU;h@=R5cL_4~(90E^fefQlKp%&Hi~oQiqqDyFfZ(&>_v zElYMqQmZi(VtC9DJ>gcyv>8&B5B!AdrlXhbR^adZuHem0y5KiVFSEd~RxzBW?tKin zD}t8p95;NwrJJ@dT$@|E*Q%ZBd%P(QxD|+^2EW<&h-m&rFYW@ z3`)tV35G<)w8dV~tP1xnuUaG-sW=9=4!CPdzAIE@Gz?(S%C;@slEpnwkYuAz$1;l) zpF+8+F@$r|Wd?QUlObBZ>DXQjYYeg6VX<76C(&w9uM3wUbXX+LsnGcY3 zilNY-8HTakwY@RuN%;6@jT8B;`g)!o&8*!U%Nf@0tc`uT0L-|5P zud?2w9O)|Gp*sqxOmtw4CHj$y3iS#*Q1x1QeN*nR_sU9;U zouHPcu4voJVK6kg&yTRZV{ytu1Y(7e*jt%SbP8g literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader$2.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader$2.class new file mode 100644 index 0000000000000000000000000000000000000000..f1d39fe9462da1548636d8bc0f4e079c408fcc7b GIT binary patch literal 1094 zcmbVL>rN9v6#k~&cA+dnK(2y_7TFeMxk-!|jcvhfQZb>ViSldMPGw}fTX$!T_z1p% zK7)TW5fXp+06vuQ%t8z%CMMlv&wS_1neW_Ye*XIY1HdXa`(ff%0evWHu}~oOc0U$j zYg95(HnGHzS4T1~t}xuMdtt|k-y}Q|N!JOFkCf^)`_#rJEF<`L{$9H zJKht#C890jcqjv@9x-g$y^@rg3`R9<35KD%48(5IITX=8KlI5mQV%`uH+dwreql6p z;tXK0+#nE9)#q_6$nv1a9ExjHiYbG(&lLqV?SqQzmRu_DFlo0%#E?0tkQTPvu}}<* zwsKyW1cdXEh!dYcVf&pYx=MyYY~l{-jWCHku_JXIQ~&DU@@xKoQr6Mq6s)2EBtmdMj*rST~tahW-Iqbf*Rh zZIG@lh4Ruju<{u)Us9hdB=h70JjM`7?N449#we{!kBQD{h7T~1qtz}i&CH%5yJ?IW zpDEhyf%SX32UzjWb6b(6)Kp#0a4R?V7aG_Z#CN2E+gW literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader$FillableInflaterInputStream.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader$FillableInflaterInputStream.class new file mode 100644 index 0000000000000000000000000000000000000000..ba46bab0e7938aee4481b1a19d2b295407c506eb GIT binary patch literal 816 zcmb_aO-~y!6dWgkrC}*8-xOLv;y?khR7hM>aVVlvq=-rhO3!BF2!rF@?s^gMuQ(y~ z&>z5$LW~1NZJ`{h?%}=X@$C4`v#)Qy{{Zj-3sqDwmj6l+-XUYaRh@X5Iapm=zk;~z6NVV8BmzwmTX@0B3y?;9gxOaw zF-j3%y~69hEN8~-Ww*HF_Xbw4Q2JA}%}&1dMZ-JNz32pgs1TW?$Q0`mrV%n%iIwpN H!x*{+C0^19 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/NameValueBlockReader.class new file mode 100644 index 0000000000000000000000000000000000000000..1e68a7850eb136492fa7be458c3a418ae99a61b6 GIT binary patch literal 3557 zcmbtW+jA3j6#h0%vSC?D3A9jJFqH~zp`;)n&{Cy9HP8!ECUXkfo6y2T%}n;U``dHA^PTJd{{H8;KLBjN-FaAp z;~E-pLWQBB38UjeFFg2(c6p0}f!x}VL@^Dh_PN}d}jA&Sh6CpUVrsR^A%V`be z$b^tp;c8floJO@X8dl-$5YEoWD9*{wJ1Wj=ScwZ_=iLx4YIqOttGE=xWf8t2hOVmk zK*fhDK2lKAY1y_hV4E>#&^BB%6LZozx6jR(#)twv<~U|%mu+OTW>x_dR5-?n*>Bi6 zv%^j$PQ@Gr)m)&mc{s3yGS}nB<)7vPLXdff7>?Y_lB8ZC9|YVTy1u*~Wea z{#~i0Nq{cPF?(_&17_x+#7055E0r+pej{Vab79l(4qJ@M);W4Xrap`DtDKdNf^v5_ zlX6|#oXkeZD&&Yhcse=PvZLp$baXO%#0)ca$huikYYiAy*Y`3qPrh&QxZ^aQB=| zm}%EaIby>$ogsHvK~-sZN7Iubt}nt7(rq)Twi8I3LM5eneb$g;xVa2@teNTeQy}Ii zQ;sR+MfVkyHAp#V5=t*33YIh!B3K%yz`&?0f$$yeP!LGisVvQEMk2xbt8Zy(QPA2j z*8*u|+4{~BVhV2~AKK=O7xMr&5U?+m%Op(p5!qIkR*TnT>!l`i&a;g=Uc~Dx^EvkF z2GPGZcm2Hm>k1Cc(f%`Lg)sYAM-+_e(x(hDk=dl98S8a?f=}5>lY+6{sj8b)FDi|W zoMm%VQNE;iB5jeD?GYWH;d8m%&~X!eV&e;TL8)YWWJAlwP1_@rCiBg{Gm|k!r4vNw zOC1M9d#~`yPv-SrM@4q*h_tBqO2^muM#p~1UtON})Wn#jBXxW$Xy1u+`9_P8DG5I)rnM>}G%nS;Nv9}ymT8h9#c#JLmfX_|liMvR*X0QE+DN2k9?M?ld2Ao*(M3Dmc!_VCJR8`GZG56NY)2~@ zlw&p8c;}LwhF%+8D$FN{W?H#O~KzV!u3*+Oc z2rn8#xONPS$FO7^m4DVQ^5cG~L{+K81eV5Y1HF2{U+J&Chi!DZdV3&$4OR!n zu>3X_h>>uOU^Z6=enqVhhnuT|-pv)i^3%V6QGP}91IDa8zHSW9i736$a1TH7=vkJJ z&|c;NILh6(cy|m{IL>?+jK~1`kmQbuAq--K*DQu{6&A;6DwqqQx)2#1l{kn))D{Xs zt}7W6MW%Xz#1=jY)sRPG^|X5$C4g(J zM12uV0C8z4Dj#8SdCJl}Vp8{-CV7NiGdo6=C+A^^2HwmUf{#TiHjiN~*X6`hIarz) MF3FVqB;Ne}2YQWx%m4rY literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Ping.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Ping.class new file mode 100644 index 0000000000000000000000000000000000000000..effab56afdc1228e26e7cd22fed453dcc72b0ebc GIT binary patch literal 1433 zcma)6Yg5xe6g^uCX-hzgSfnTqD_Uwxz_+3(iq7EF#|-EUelnyh1kfl-ujo;$ zS!L!loJ}E#VhZPQUY)$4%td7`?H}LMa9P6@fo{hPtWANb@|O9^G{V4k49jz^(D$Vq z7`MI94VJvuZdo0h7l_yC77+IY627#g{Yq8@dal{79V`fR<)@$U&~2|G1rC*MS3U@< z>(XB}*ByEW%bsOAPfXud>&O`oHto7VzHE6_qy929eHqpa@5N>i)C}7Vr0<%JQLk0r z8joyuBT9m-T9g3!Ez`B6BhcqF;mWFS*H-N+37HQwP2G88$y#80Ze7Dwfn5IH-^*1& zk6FpQiqZnEypYw#L;3{9{}V)_6)*HHdDm9OCRMgGN>&|5F+$n{NUV;|>o|-d9Y>JS zF^mkE8_Qa2A+{FZMb|dsg&}lrLu(F+PdpOCC~XGa zw8t4Xf&oGd(>uoZ7`=KEio0W65wt~fKcX2ee1=Bkckj{r4av1#q<$2>pqET-ihgDf zOfvryB*=9@kG7yETF_PmT_SWsL4QF1KFfzcSrXid??7*p4Kf@!#f(p53V9SU-9cDt z5l*%UpHl%P+3bG^RT3$=jel_#$yp-f3=F<){bnOh!SZudUA5^(RAjoDf1jdO`0^t+ zn~hO_D&P|MkLmzRM_?zpr#d~w?*z+j!ak!zUs@ks?L_ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Settings.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Settings.class new file mode 100644 index 0000000000000000000000000000000000000000..4f5de3761f340356f2787343b6beeb6570b01228 GIT binary patch literal 3491 zcmb7GU2_v<6h515nlz-4ex8YvnasQUoIUS(o^#Iokw5-^ z@|1{<({h;hQn{OYXqF9gY?x=mLKwqEHe3qRWxB%NR5rZN28|7iL8=6)%F$>#lTDQ* zMHO?RBBmsDR?MaIvuaUX$Z*7o9Q6o|dehSCR#~gHbU$%~-&j^kO{;>GNy%zK&XmP` zsVL2>g^XMji%KS~7Bh+>=BA5&NaYa3`J$FnQVD^(T~FrV<0x7xNcmJ+ol51>vtn8~ z&ru(A0Q=ip`|vR3V=eO0t~EDQZ!XGpQMyo#!aBX%=R4 zX*MIk(V!b$&M0y!S5)PcVu$PEsJ}xs*t{S|2LwrE3_?a$#H=V_l3LCPN?x{W#=Jrt z4P+%05rPysFRA&0BIa|pnr@B)0#Z1JK4C7Wy2o5`YXSw?-ic^Z^s zq9`&lp8+{RqnfR0%Lo&&g+a-pfeZph6LX+wOdMZ;ad{I!bYQ7Hqs!Ertr~M`8n+-4 zIpAv_TuW=UhE|=@>eY3lYOSCkReec=ue~NwZuq1d>-8O8QJCdMt6o)1V@)wu5pxKp z8SMtvbfsmQdfh5ormn3*?_PWn+BRXmj#Ofvpt5e6TD>W27Gf|q5oI>C+N@EpHr9)_ z+yg8?%|J{+H!WkysKC3dSFDEFb{I68*;->A+?Ls>rHv-5J&2GeO0vgj7TR5Aw!o@x zE`uvM_J6v;+Q1o@-LO`4lcR94(K0J~)?hvF*=*XxRqeVKp;zg6geE8%p`#Ry&@nc= z!iGFeGB_C|Jwi+LPK3@d%Q^OTmJLVg4UQ7KUnSVyj51l%>dVRe;#Jgyquwo(h_$uM z^oFoj1T@ToxE`EtMEx{O`zVSdrx(aaeZc)5JODhn1IIjg2;YZ2nE8)*F#GK64CJQ;fLhA4}*_h!x+YsP30*~C-D|(JJaiQ3W!)Ioj`xV zCjd)zH1U9ZPk$u-K0kWn6rY%XK>k7g&O`FY`P<)6FEjAAfxkyl2l+m_{gC*0VACOB zI|LjDAlo6pLXYmxZ|OS$MMTroP3NKY0$MGh9Wy9#4(S$ROwB-h|o`O;f-ZorML0sN6Zr9M3En{h3w>8f)6```;p}&bot}Z9z;sK{}-6O z<-3fjS8UpY?I|v8zeCG|gi$bB>=1{7^@dr3cG?qLVY}=uRP2zkwu>7w=w^cb<^)=T z57Qd=PbNk;s0%{lfjjnlkiGMFCgWStS+|K+Fvq|ax{7*U^N5eTOmT7J;_QD}g4`VOSu zdw^+}2NA5kB1IvU609yBUw;f;t6qjug=PsPr#6z856` literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Spdy3$Reader.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Spdy3$Reader.class new file mode 100644 index 0000000000000000000000000000000000000000..82fa542c20f2418494eae083cae06eac907645a2 GIT binary patch literal 7039 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 Ou|^+2$`;~yukZh@Qi|;W literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Spdy3$Writer.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Spdy3$Writer.class new file mode 100644 index 0000000000000000000000000000000000000000..2f4c0904641236991277734ae07332d05d91387f GIT binary patch literal 6511 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Spdy3.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/Spdy3.class new file mode 100644 index 0000000000000000000000000000000000000000..8b29f1c5b767215b350c76653dd89c45a08250d2 GIT binary patch literal 3656 zcmbVPZFAek5nf0XA<>j9%ZaPJv_@Jtv20QVNzj&KJ1r$q5^b4ONlJ?Brs@eek+8u7 zd_3qSpZah5wP|PKnP#T#=lrNl_iz9OrEco!NCfZM+k5uq_72PMfB5@90H6#`4z9wc z4qG{xfTj*la*%5GrgyN@I9#vy>KbTG4QAJTHWGx1J>rFQ68!)Tu0~4TgVtfU z*J;$BNwKEE+*sUc>}(%M=|rO3>Go2}lSr(T8@*n$wb_-rnZ$al-QJOcsYI}YDpHWu z;7YV?vt8e>M+S5ZB@%5l>g$b8L^Q3zLL}R7w$|JGhr2r%PeT&SB<`$r8taW#uUX%g z;&~0GH@54Wha1h72G^tEZmYT8>@?PT&33E4t%1IW>^RmSx879J&VdFKFIF*ok6h-8 zFEp6Ey|kx6X3cjfTH1CQZH2=l%6sI>yU67 z1||R1K!~8^GTbdjywWIe&P!ceFY4HAA*)T-gb14&86wj6Yq>#2Q?6*Vl|2UwS(1A%mL<2X*9$ezXEqa7L zs61re7e_aom%3S|a(_TpjSkAxadVk*@r>rjshs=$=s z#E!>VV#_Gi#GC>}dqDVz#=@(ykj80Is)^JitRIqo%r+bAa+K28waM}96!AR&RIQ&S zp&0nw{hG)O$14S_JvYjPGc1nkH{#tI-iIxyEqnK_Hi!J_9*L% zfiiQUi>K?t*p)8HXg<&QL-6N-;~%0*plg9f8Y}EM<BbOzcIE!-TGn&?wOH)2xM;NlVF2?&?jA@k% z)83^tFG z<658I>h*R?<>hj0Jmhh~XM^y_b8RKg;VH!P;Jnp ztnxjpe7|N^YNl0_R8^zpvtnJHSBwsA8%>7gfR%~yR7?vMj5T#Gs%F`E=ATf<*rBMv zFw@?-g=ttNj?tm7Lpl-`>g=-Q0-%nCCN_M2?c?p@(uZfFk^!r8P5ne>H){^bK^Is?Fj5Vl)%*BR?-~&)Jsx>#YjzFwxv3Dgj^O!v{@Q__KxpI z4dyRM+D9+(vc#_De=m;OA=z1caM4Lz?qsl~`tV}zQdjU?_FJF)q>)|WdKyga_BIYz zkVth64BMqRv!yll#>7rRW#KJz*wZm=l{9$o_L3rqQiZ)1UNyKd6}ggOw}RKo>ba23 z^^Ms1^qQp?t6*ZEeihs4d3-Lyd+R7Q;yWpP7jYqlrGLc~mi{fLu=Eeh5o62X2iq=; zw2GrDerxzWb>|Ie-{4>ZEPTq}Hvl*B7r{-a;V7?^;2zvZq`?Y2z^5eGLPFWW=e~o9 zgS#KUfyuuhQY_hM)r*M1P+BpAwD37RjOKIj2p;1K4ZeWi{3mNBVx9Ui>*0T4{Vmil zu};J4IM}ZuD*zuYWd92Kw=n%J%=`^0sKs0Y9!Mlj^^MxEdCo=PFo`Y literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$1.class new file mode 100644 index 0000000000000000000000000000000000000000..edb3899f4f48ff21dc4ecb256e511faf4eb3eb78 GIT binary patch literal 1233 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$Reader$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$Reader$1.class new file mode 100644 index 0000000000000000000000000000000000000000..968e27f6b726770a739904990b440a77ec3e82f3 GIT binary patch literal 1703 zcmbVN+fEZv6kVq+3~dL&Rtn+`v}!4rY4L(sL=8b{QosNq5ub+X2_2kEotXl@`3HW6 z&m<7MB>L{Jn0WgD<362+VoJ#1Je;%7nZ4Iu`!@6S&&SUI@^~CY3^&D+i6M@mD7ui1 zVHhKEjABfJA|V$;2l5ieCEQ}@+)|CS#kZF|hpQ&TSV^-@#eG#%9bT&{_REUrRTbUx zxMQh?;#SMAm1SCd{Q^U~SJB-x;oT;AiK}JqFvvyA;?9hrx-NGaCIf=b*kq=8x^1O> zB!NGrTe>&R@HX?`D5XtxOH~Zj+E9qMZfz7^9JyLt-z2Anfas0DhgKOPGj^FXbd_|A zFVxI+?yRWm2Hhk|wx$}Zs-uf@<1!)=#Q=t&u3FNO&Qn4{J2~N@B_#1C&yYMOGzN+9 zaINMMw{S*KXC(Fb7`m+#7iV`gUKNQa2eDWS}099$)0Gtpqji)UM;_P6DKMk4nT_|N^+&%{#4|rnYFcIvFInb=IMq~ z(%nEUHs?dkQ)d-Kp)#4)N*_~Uq3TZ}HOF|sR&ItsRnMI^Y=*e1Y22mZpU9C{^Yrss z7z)6&Xc05&G=K2sRI6-ohX@C#)3K&hCx>fX-=gl$2jzTZ>idpXWToQR+oEr%SQw!1 zZk)cuq3&)m1pw_d65=8Nz6zJ&_&W2g{z1>?4#N89hLFx2~I_wViaq zzM+@o0n#UJ^r4@2Azi>l!W7aaT&A}SS4hi8H|Z?i4QBVi_7HiGHj+Xg&>q4&be2A$ z83qKXL|kurPb=q literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$Reader.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection$Reader.class new file mode 100644 index 0000000000000000000000000000000000000000..26970877e19d88f234653c8b0825d05c2374612a GIT binary patch literal 8667 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 g>cLYG+AG+WzfJr%hM)75u-0Ne&r+5i9m literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyConnection.class new file mode 100644 index 0000000000000000000000000000000000000000..a29138f73d614cded41d887a3500d4d8beec8602 GIT binary patch literal 14356 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 XG1%cg^!tHq1Lozg!RS!7P=9{~>+iWX literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyStream$1.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyStream$1.class new file mode 100644 index 0000000000000000000000000000000000000000..bafbff5cb93ea92034d88d2fa0b08165af809dc9 GIT binary patch literal 249 zcmb7>B)M%}LEBoBz$|adM;;uh>*}oTiZ2^eXzOcJ?J1mW8Dk=_D(qGI zTdN$kjkK3j2#u^wAZL`8o*D87T4VwcnC^@rx7Nyg@&ajxms*)h9*$=!g23`0YC30T Zk6-Dk&jPy$1KtsaJjdJ#XGG`H(H92+LWBSS literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyStream$SpdyDataInputStream.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyStream$SpdyDataInputStream.class new file mode 100644 index 0000000000000000000000000000000000000000..0d4a2a83ead342f5420a8e1292e7057b58e0513d GIT binary patch literal 5723 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 aU|jlZ0()q#BG0wZzohP`)x$KSGVni7J+24< literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyStream.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/spdy/SpdyStream.class new file mode 100644 index 0000000000000000000000000000000000000000..30005afbbd6a7e133f97f6b32fc121eb5fbb5dca GIT binary patch literal 10328 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 SXg4R%*2u0?WSJs9tb7A3=&vdO literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/tls/DistinguishedNameParser.class b/platforms/android/CordovaLib/ant-build/classes/com/squareup/okhttp/internal/tls/DistinguishedNameParser.class new file mode 100644 index 0000000000000000000000000000000000000000..9ff1a94c706d67cc8423b3c4c19a71484d3d9ac0 GIT binary patch literal 5095 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$1.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$1.class new file mode 100644 index 0000000000000000000000000000000000000000..dce73cfdf72e2d78e3f0dcabc5003d738dbee09d GIT binary patch literal 843 zcmZ`&Ymd@E6g>k-OScN5;=1c&ALs(BTS@$enrw(BngWR!O!nKfOrTh2nm%^dpJlRY z;s<|#KgxJZNl?>m(s`V@J?Gqer@wyx_z9qkqY5Ws6AmQ_0?1`RBca+ zVe-il;d}1*gw$>2a(}`@FWs-eQYy><2J?-SBJBG-iUc8BmuNJ*WThA;lEzl5XN*-6 zy5hB$YUpJ3Xu(f88F(dKUqzmr4MaRwQw@(y9H3>wz=jDE4HIp27_=zxQfaat#VXKn zXyP%RP%ZLH(d;tRQVq-Ja%PR3g>Yj^ZwUh27&ZbG#RCyVd`6BB@*J;o$O_VHPq0H*Pp8&az-qO$>~tdw^qROz=rvkBqkW1P zox`tSo$n}oS;kapEK>|%qei2-TpPHKo3vxNg~p2E1&YhFYUcv%0>yf%e&rj=YZ_xI jFeJIrUsTlA&p4t8Udj9~hhjauZm@^Q7+A!Tj%6JyI#wA%&8pK#?J^__ zo?o$eo!eDm*`8na+T1#+*AEGE(X4u99cw1m5jPP=#Dt-|6gG5hs`M5~AFe!=V~8qB%jL3SU6pFW zZjzdx)OAbBzQn|E3L4UO1^4r6s|R0Wm#oK8a<8IzKkD*mhmKfnjk zSAW#vOtN17o*^AKWK>vX z7%yv6_j!{C4dDmc)bus?cbm;E!fZ<=;~j>n8_a3bHh{V4(W`L|c2|Qzvtk;fR3}J*ah94O1GHjB! wxNPwb><-BXq&_IzHu(!ReEmd|?b0OilMW^@hF|1U^!z3;Op!~3edOtT2fZGYy#N3J literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$4.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$4.class new file mode 100644 index 0000000000000000000000000000000000000000..f0fd75ee2892ab0947507ad1f782a17ff41b7790 GIT binary patch literal 691 zcmZ`%T}vB56g`u#P1bFVskNH4)o8RaLf1l`+ES39w2-!-l7Mfsn;{upXTt7A>CYdhdbxqb7yY;{rL;v9qI*SQMQporGRC;wDAhBEv#BtvruKo z#RD1Db{Ur2I_$fA$o+wEeI54n1$Xy`!w*#RQ7RdKVyM&~E86ZbWLml>80OnjiEpEG zPlU(Z3kWH-waIDG{~;9z}wX@*_QJO&TQ~juhFt>1QA5QRs^U zX?o;o)VHVng3|!|$`5oTRsXAq2fAlr-N6PH9pq7PV4J9hO$%EFenZk{E3Y*fiiXk+ zxazy#y;I@Gq-F{oj+7cpT$)Y6Fz0dq?6Ztw9sXdjE``^T;*w!wmde(6?cH$^$*sezrY&TNc~J|o{%*sfg3y}>m;#_ zd6Xz)c!tFZ!+Y|k&S_kMT_OD&neLRsPS|g$-`zbPXTp=lb2^#A5?+wc&`Vsw0!214 IX35j{A7fCJ+W-In literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$5.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App$5.class new file mode 100644 index 0000000000000000000000000000000000000000..8a7b7d29bcda138075bba9ddd58c9feb04db67cf GIT binary patch literal 1755 zcmah~-&Yz(6#hnuyKGiPq6W21jj<7lf!J#LgET23Dh+~FYSJ{R9hMO`CA)NYHOXt6 zeLatl=g;QSqsqeF&73?qe%iWL=E4Xen>{WTTqDmJ8lHW>!Iy6Mi|V2BlLr$w?Rbu9 z)hLGIdwb?FOq}u44nU%qzDp_GX%;~+25rYaa160#N)=QRGbzK7L^;c7*e-?J6kgq~ zDk$nGVN1sZCUs0O$DWQKK>Wg98$fDE zRp_grqQgK{hma1te3aJKHcF+t1hx0~>$d%)j(rIkIu4UxE##;{%&HV3*1OSWmyeU} z6m-S0dDY;q7gXJ081MZ$!y1+7u`s;!`~xa?ox3^NX{R7Tn@PwJMQ%+4;MHzlZD5!CPK(a8lW7;~ zd8(86CbxJ^kWd$L_siRvR*&ojh3+k1p|sAxOoq801kT2naw<8Lsp?uR*)r zYk}xcUG7n}lOTrkP22T0h3gXk|K-w_nz)=uw9}1|?(}5?Vw!H#7+tI^5|IautUmfp z;XS&9-Y08`=5j?#Tzd_cc!R#*e9R?!4iE-R!3SjP(uPL{~cj}XDX^i&%cG9cm?(fgVCYr@DU=vVwDgh z9Ypj5;)0KuA;hSUh>?%66Nqs_9CN>kL83W`2phr#8^$z?Ai+kk$f8(bqbRU3x@pEy zWieQ60tajozpzVwt_jL#n$G=I%u#NXS&+4~;+Xf9c!312k#hZ5AVeRoBS~Y3{)cX0 MhAfRx7ipx=e-9hHGynhq literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/App.class new file mode 100644 index 0000000000000000000000000000000000000000..f04b639f3cc019660a15865fb25e223d43219464 GIT binary patch literal 6374 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/AuthenticationToken.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/AuthenticationToken.class new file mode 100644 index 0000000000000000000000000000000000000000..e2d41e3f107c1e6f491fa2f28f89e80b355dc6ba GIT binary patch literal 776 zcma)($xZ@65QhI|8JCK?kDK7bEp ztR4v{j)|G1x~rzD{;#UvKVIJe9AG1jI7%tRu%gVWhBXcA3`yS=PJ<5xL$2QEcib3o zt7|kpM_Sz@`aj~Xdv7~842ffDNw3BbEmztMv2*)|sVCR&QYkU)zxGURWtR{P1|=&aUm6YDFkI-ZAC{4X&nh@I+D;Bw*NN=!@_i_mz};a zJ#5ncoe!ITc!40#5fOhv0NV2?qXPBsw)OPHg({*{1vWXU5jERy|M z{DjEEOz~D|aSlu4;#$B)Qq`SjM5fYdiUYgExfgUO27Y2Juh7&yiaH+(5}gG(3%{n;6x3gNO&|B6o3o5wS71j86R@&{1+7x1s}jiA=VZJ z70ukv-0Ym@zP>*`0i0qtf{X1ClMp)u|MF`3ctfBk!f0meWy^J&a@A>9+(Zb@O>No> zf_r$B61Ep6j0NLi_A$byF!=*P2jd?n!br6M literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CallbackContext.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CallbackContext.class new file mode 100644 index 0000000000000000000000000000000000000000..41b4cfd37426c6cb8aff3dc25cf88c800ae78648 GIT binary patch literal 3216 zcma)9+fx%~6#s1qB*f*G;=Q#I5knG9)p{u?w+Ir6pg^IB)-K5!7DG1fZbWC=$M&&4 zw-0^wr4OZ3p;KqtnL2&xAJysa+g(Bk8_WaeeBaq~e&_yW`1ij*{seFlFGKhclW8~LPCQnIURGOHUook%H%FFHyD3qH|` znz^ddRC*wxBfCmp^fSL|s7lVHG%ca!29>NK3D=|h18Trc|AGX6O3yLaj*M1Rr_1Xr zsxhyu6etO2bSAK%7@D}dLcg`D(Rr^YxSKA^V5u)GCK1xiiAowx(S9b#ab`tHn^nWm4HkP&FB@5PLKDsF-l?bCj0<93Wt_vPj0jH2IE@||XV5F- zEc)!(wFl8D9pkH=@3FF0$fEkGWt_^I59715GqYUyll=JvnsEXj;S{)L zy!p_=KfVa|nU8|a`7YR;PXl>7bblnIpzBR{wga2n9d=TI*wlHo3%8r5y zDB+We@io`DjmFJCA>e-ve^V_;vI?ZF0&)?TXe<(~j==XzO$3*#jGHUQe2HA+f0(Q& z!=u>J-M>W&Kj1>RC|JAqa(CBV{g&5^ee*gZG5nW?%mFZ?C+E8Y`O}y zvx3^m2nJl#!2?had!XJY>TF$9G0q~^8wa2s@j!h*)aAOUH(k`B15l58pk|4htBX49 zqK?!4`eU{GO<<>Y|Eb`jFzV`)~_7d5Drl K{zFh4IsQMgYOV1A literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/Config.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/Config.class new file mode 100644 index 0000000000000000000000000000000000000000..19d9a6fda8d81dbd33db2c241fc28113cb33a3dc GIT binary patch literal 2668 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 B10DbX literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$2.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$2.class new file mode 100644 index 0000000000000000000000000000000000000000..c92f1faf390368ffee7a6ea3c8be75a5d0919b9b GIT binary patch literal 1049 zcma)5U2hUW6g|UIwrtlH5o4)e{a7n3P+Ih@rimdnHc~Z3F=^t%uuNc@?GD*pX#80w zr6xZ31N>3OJ3xYwXiLI9cP=OA-Z_`~`Rn@+0DE|z#v;~r*wA6qLK<5Z9>Gadcw%82 zPfZj|6iv7csUi2BbHU&=RM@TZKKFW}>Z!1!hP+yz;7c!-Lm7YBXRtM2grN#QhCV~K zamI<~^PpR8#-R+l#7V_H89BR@ypVy64;VfdZlZo8&RoA@iy>K89lFCxLk8mQ;Jhuu z54`PDCEHLQ_gg%a`aCTr^?VGV+Z+Xf2y;Wp(kER z-7oi-V>^0W8tgFed=-&B$0F{jj){_uGAcG!VB1*I;TD!{WUyvqM~5nQP3+mI;TbLG z`rSA+hRn>IckMIb#bm&&bTSBni7T7e%hAj#I1!$ZL(w_Z`(`K-7U<|ae6wb4Pxn6U-PJU z%=`Pr7S`!mq-psUj7&y*4-k_5W2A-9J4(|V9o@WVUS=6 krcuVKQTanSKNU7`pX3vGfQN)hdf<<7k1~r|EE3Y^H<)n*1^@s6 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$3.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$3.class new file mode 100644 index 0000000000000000000000000000000000000000..cb27cec1ed431cae863b62e2f5f4b0d9d0c4bb7d GIT binary patch literal 1416 zcma)6?M@Rx6g|^zyQMBr78Fs?f>pLfC?5jyp#r67p+Ev!BmcJB5r!6vOx676l$A zS%)n9XbPLccb-js`~y)*jFYn{9O1uYC>uBFxObDHRtBw^WPu@=aZB{7oq6H#t?E&c zdvDF6O&LA!TBcnvJt5;}GAJoCfI-VS4)-#)S*dW!Jh=g<#1u_I@v1Z+#gM(DyKdF9 z_?nRYdM*uiOpcISoB?jN`%70Vh{kkQbOyBcoej)q?8_2Hg|`w|8)tYH;d z6>Az^;|)XCa=B~^%ao@R&w8HgG4x(OqLr$!OWf0t!#YDCZjc(18a9xpXnRA$Cbmcu z*GnQX#SpvLeY<$bEs~agk=m&`&iRywuHTMk;5s|p;^LT>n&b^5*Ls|-898LtESC#{ ze`0v_pEG*Ti?WCgXz<^Rnneul748>AMHETQ{t1c5$jMe=YQ>!r!>DlumzGp>;M6nX zyXT(?$-qdq6jFs&5|y%To;2To{)z^z%UUyg$pYeZUv!g#dk~7nq<{djq@ji-88s{^ zsbNWFboB)2KY$0c>LGdS6o<*iQzJF7RDTVD)MyP#sxMeWFx3~TA(T2p_*-LToG?r) zp-f?rd`l3gc{GXsZ#{LVu_4$3N;p~BO-mh?FXVC&Txx@U>%y? zPC$N0`W*yybm}om1nTIzXs#nj&8ML%Gw4=kv8v4dMI_rKqQD>u0VI(k8>B1pDH7yG KiIPs1et!V{|6(Bk literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$4$1.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$4$1.class new file mode 100644 index 0000000000000000000000000000000000000000..b926c566e532ab9a461e2d12c7d6e727b08d7dbb GIT binary patch literal 1063 zcma)5%Wl&^6g?BCb{;MXp}bn4X>dy(5EBTnC_+MkN)c%z1nPp_#2%6<&KTKFfKTBw zkO~MEd;lMXxRV4S!6LEbx%VEA&wZSkpTEBU0MNpNEG(3B$Y3Xr3a)37hohI>9QJU- zLe)aeLY=`(MlyC<7H%?t!R{(0qE5i$Si}r_y)YWO{4MuJ!u7()52xJi%!(cmbw$r3|a_ zJ1r{83RNeN-W!J9YL6>F3Z+k7s6?p5eIj`f4!aaYuem4oySgINpP>vpOZPLZy&Fky z#K5`?xfkIi^2CAEvna_aM`@`5myYIrD;QRv&ag{F-h&e$lRX~DH|TO%#p zv2hn|3-@f?N0W3|MFywEP}Hg1fUBX~ADjp;VQ`mp?)2wV>dBY}BO)sFKg3xjKZ6lX z6s=V~%Izg-NgiLuV;PgCnJEt(@m^B3>=mh?!!ZrgS>Y^^&XwiWG315v{~TGA>3U@7 zxM#tNMXdncniRbS6bU^`UYlZ#5DzC5Q`&=VOh;qoly n7B(qL(f2EqB!#QEMm9}%d>iZJZPJ%KS^ZdZL+w`3Ftfh_0f7Q| literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$4.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$4.class new file mode 100644 index 0000000000000000000000000000000000000000..b3dbdf622b4abec5b43a9b60d70a549744a00774 GIT binary patch literal 1971 zcma)7ZByGu5Pl9B3mef8g4@!h385-Aa)OhF^aZD(Sb+o(fy4v{^3tB=i>*|Vs3cSJ zwST6cGgCX$W~M)&KdRF`*#Rbu2QkC$-g$5D*_Y?^?|*;)1K>Jp8I0qm6yHektrXu$ z@x2uDS>#Ys@k16vxGlwk6hBI_sG^+32u!)SBgK*w%PQ_>aRc{Mtf*L3vBm%fZN>9M zV7fdEMaYoe=dS)rFzA*aG>UwW+f7ll{h;pe^P<_+i+1GfJJIVB!*JI>40(eNjae@_ zxw+hH6f05ScnxyNNSDZoTyn@tyVi;#-(wh(3vu8?3~ZOKj+#!WUnAp|<2li7hTro^ zKqT@xf$JpFlRLXJ+YBkwuM_e!mg9;0tyeV>Z1I}RWz6zz?r!tIk?Y=ON+!WDodA?R zN5xTs7F9yY%bS$C+h9=3Eyt~kfZ?*my?Wp~b!x+2anTh)bjRVY-_Uz5be<8A+%e=! z2e#OY9N(kgvK7A-*kaj{XvaV3-K?w#rM2YQt{+mT)nbb_>$tDsGCtEVA;o!I z(D1nw7p1s_NexplRBSL@It8Ni+|=*@4>eSz*uo}q&|ry8E& zDZ{y=ULIzv;W-Q%+9YuqMvo$F)Lsgk25{_X>tW0Dx*eW6Jsc6J?u2_Tf4vk0J~eGV zf2>8K}G!95}qwe zGlxO?Pt*{F+Ul}(giMpuLAP5EJ-?eI!b}p{()3H9_L^*yJRQyb1x#5|v zWB+0~A>}H`;Py@GFsJv0>5^oHsuR56w$ML_m8c47I}kh~-ki_(O_?Z`3Y-3K^kTiB z7b|S4AVwA6_b?%xV;t&p0+aOO=jg5e80pbb$w`1T(K6P=%vcjSV@>>wH4&J;Bm?w6 zg)iu|PSz%^RnpT&p$%qSX=A{++J<6Gq}oUs6N7CG8o6{EY2z)_H}Ux|Nv7#M6cf{A zYtkm`E96Nt%)sbH{|kfheQWP9v}626efIhrmlTMNE96lv$itKUH V@^7T8=v#UVSCGMD{Dhr!=6~GB2HOAt literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$5$1.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$5$1.class new file mode 100644 index 0000000000000000000000000000000000000000..e1733918024565b0303b3ee6ff1b56b93776ff99 GIT binary patch literal 782 zcma)4(MlUZ6g`uT*=Dn9ni_4@YHGJuBXkYugR~SRCjO)Lgt{ zD5QOv1PvD}3}EmNloF;H^CS@o!)i;LUdYdQ)E8l-O;->aJjzZb>D+4Ng14{NSCKm`Y1WJU-?|+WnZ!+e#U-=?4ue$}s~) z>ze(S*VY3QiG6AHXZ~s7(+MAPDr8SZu}-Aw9g4KCyFO-6_3;9}k4YQ7N8sXvk5yF3 zn=IA@4TiE+4`Z%+;rGsoh*E0si8>l6HR?LZBKUY?n+!n)r^$tt|I1QAMx5%QXrIx| z_uG*XLZL>JQ=pk}!OCUp0u5A--bqXmJ5A9R?JeWgH?F|y*T`Kwd{d^?X2SW6mlXRp zhKCAX5t9F?jumzY?OCaQ33dtRC-P4co)vd);W>BDWJ+Th2eXuz!yH}{=4rU!phQuH LxFVr_CPr`%?C`hX literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$5.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaActivity$5.class new file mode 100644 index 0000000000000000000000000000000000000000..5fbab5dcd02d2fdeaa4d9eb6054a9cdf1ee7326c GIT binary patch literal 2770 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�RgfRS3( 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 WR0rEl)kGGzu}Jm7_F9Op=F)#7lUJDl literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaBridge.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaBridge.class new file mode 100644 index 0000000000000000000000000000000000000000..786b6824fb3194c43f4557160141859fb63df370 GIT binary patch literal 5124 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$2.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$2.class new file mode 100644 index 0000000000000000000000000000000000000000..a29ebe2da58e6b6f2018ec88f4172199d289d812 GIT binary patch literal 1089 zcma)5+invv5Is)PY!Vg{3iQIQEi5IM(k*>MK?szB)M`s5iUQ)z*_gy-V^`iy`dvsA zBp&zxJ_<2TH&lW~WF>n%$1}5MF8=xJ`wsw*;TJK7yLMYCA&=D()^N|keFvU{b%xT2 zN1hS!FiIGf1FpJ8%dUSSI-g|X@5OJ%S51a|(wDKf#ZV2j>G}MahkfCP+I01Z`>iwC z>Ki=}tw;)$Sf8g-$>bTs&dg3z8PwVgxt8t_V*)%F*AEJkq^gQp`slil$|m z?~Xx+wf~w^{SWofgyNO7X)Ik(#?2!>;*|4C6-GLis<$tazV14xx~QS3Mjg8 z(QvTg;t?9urrEmWZ8KEtFZ_tBo`29e5@F(ClVNKz3sZ9S4${H|GNxJxLxKK<)@P%^ zP}FKKeh~>nbNK$e(CHw)6P>mcC(YoT>S1E28W$lG;(rfu?E^!$YFo58#e|v{rp;cN zm`q6@tMsPwG+Yicm5OZuK$5ya?=C~j#bvs^LZ>IBXGxapjZ?7t#wjxOZ^(Wg8{kNW(lQX#*GPUy%8V+_`^gjBBEDJdUw&W|zhw4=iGdyt7y) c{|s*87RelL;|{LTX`Zk-lJ;}(01xxU-Pj~~{)zi7;rU7j zs>8i%cdxdzIuzAViYPHTYci6_3x@TflLj)F+hxdARUjBjbs32_?Zbx9?|365&sbgg zJly448oTGr8O97?uxn8ybT#C0EXd;ySwVS)Y8X+`mN;futMsY)DoUt8Z(Z_GHEU$( zJ?@LuT0f#A#gRv88yzFW+((ikNP`(>`ay$W7_0+v+%1*Wh=DLD4CDRG|KX{LJF2aH z@k$ykCNAm4(mwBS5^f{%Llw)Y`C23`6`o{Vfrj)K;?KqZ!%BA zX(8h{MtgvEY6QL84E=44(&;t&dQNth_L4h)3g#}HBIEu<_FEcQqSe3v8V;>?`dz|x z+$4+P7H;=o0)okr&zZ8m!gjwS^8>l;N$!Mv85o?g^t?^PjtJ*7UH&D-bh~*yOhUjo rCenKxOyW*T*TG#(5zQ>_rFi!-O?!^YoWYG0J43kLpM^Qh=L`P;k%>1t literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$4.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$4.class new file mode 100644 index 0000000000000000000000000000000000000000..f02667b97eff747caed598045294009305ed74ef GIT binary patch literal 1112 zcma)5ZEq4m5Pp`o19}S9m$tr@Dy=|Y&L;h0Fn*z$K(I}$LF2dO*uu8QuGu@_e;EBC zCRP(a_yhb=#<>F|(Gt1jc6MfGW}jzf_UEtfKLG4wKZ7I+;j)oM3J+tv7?Fq-#rlW`4 zsf}f=XLMiGJSkKV#ypiu2G1A{7Y>?>pxk0e)O1HM_SHXQ6y%NFZc@qi&8Ug3CLb)Dn(nQ#LO)N^M#7juXgkHxu0c#QM}{4u2Hrfu(5DEX4Bpumb=|Y6m^S82vV`(CJm$Js~|#GFREY z0ITd=AXfQ?_~*zmM{Ae{_<%gEcC^po8g7ura1*yCX&NNMH0jD0#J(aii_b>-y{b`U9dcFo=af5qsp zFtM8W!5`p{GR_?!iI&JEx3e=lGy6O9L7Votd$ zs`U_MsuNimHva3+kR0`-+hbsL>cxp37+1WIA*IzzO1gK(hn)C7SFWdhsk$#k(9<0Y z6&u^wv601+jWjYgZ0uUtv*BQuTDDlniU$n&@CwJ{s_PuL&x9LTpq@L^xtK$|cswpr zQ~FdFVF=?tmaWA=Ff3`+@M~I~O4Da}JFEI+DBp;7ONvpoIfHr<7^=o)mMQSR2fF-@ zAzljGwKB(r8tHQ73XfrZ>N1Bu3iQ5GG-wuL`Fz*_fFyN;-e8P=8&~M`D(#+-9w(Wr zY+ry?b}kUBd_(+mn{B=Wq=-NMpE(Taz>ml3|*3iaMk0U! literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$6.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$6.class new file mode 100644 index 0000000000000000000000000000000000000000..85510a0c57bfaecdf6da63dd5cb0a3aeb04d4ce7 GIT binary patch literal 1091 zcma)5+iuf95IviuagrJm3iQIQEtrx^smn_x6oimmkXi*QQ4|nw8+)5Ofc;Ey0D8x8*hy;y@rQO*%J2O6W*`L3@{{Zj+ZV_|1m29gettB8Mr5+^G?R@e)Mv5)nv%WJsCOM4Aqu4U6;S-eowf*Hh~^; z*E^G5&*;AJLMc?7_&kzI#*Z0xXLg#(pw?!{c{&gb<(5?9#h~92<`wURger<|WEKh%*_-RC0i>A*tOMh$fvCCu9> zplHKJ!@{PG`)E*`X6ur(!%#_n;f7pw-Gk1t@M8;G4BO*bn3Ah=kQSyTBdUck6zE@Q zV>TKL^IGjko>oWF^cmhvN}Z14Ytd;-anfu}$R5Uq>Tw=2rvCRB*WNN@t4WiVrkGIs z{IuPxW0NTbz#6@(JdKxyOr?^v03b>IpqH1SW#a4 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$7.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$7.class new file mode 100644 index 0000000000000000000000000000000000000000..b8f243857ea5746b9815b78bc29ff65a583d45f7 GIT binary patch literal 1190 zcma)5T~8B16g|_Hu9U^D_yH)2XvMO8Eb0R>5MK%=#VUyyG`>xDhjw6@F}q6%|Hj0` zXu^w$XySuEz#nD2v;80vnzTu0_TIVo%(?g6`SbVJZvc<*WEexZXO{Z~bCw91fAnldgeGn8vOYIytu_nX4= zbrk3p_bTnZ(v0+hsDx6e#N@0=C6i|i>jNkCWiYqHkgMoGFcfQ2iC2dQbrHSc^^iPc zHSP0ohey)b9cRukW&nd-RZ2vakjJqgk2_!mr4_1SNUIm(m|?BlqvmUsP=VgMc4awqe7wux!)lc%=1U zQkPa39CL*ia@Fv*>U+XZEIejd><(0)VoO`5yEPe8Lq)_edd{95i~z%kR-17}t6do# zFuXext24=OMSX`vS*@MX+)g6u#6_Mi>GQ9^2$?OLNgVGJLPGmo`66VP?uPU!9e3$b z=4m=DWE{sdAE2F-pog2Gzl~8ky-Z(E$b&o2BA5;s%24sKzJXl8Lc#k+%P+H+Lq46dfw8NzMnZ81?@c@AS1%Aht>8&P?yUbMCq4_S^3-UjZ!RMG^_zmP<}9`4p1SQkcWM+%2TA z2wlOFf@KAF8Ip&FofS^K5ipFG4af3aVd+g_Re7MVTO!!zAAGfakFys|F> z{k8wra}VmlJMK4Z=^GDf!p|--^U99k z&BAF;`?~2?(#h6+sWUkF4-C^fMGOuI$mO&>}EKpEtsNzpCpY;3ej|0N(CTGYH3;0 z5B*(5=sS!N^14L3H9E)0X0*9uFm3)A5pCfZQSCEgpIY7-TI1vme8(uQYHOdtWsK8_ z;VQ0ma#_7xM~IwY-~{mv?Fi9@6DVP>i-=O(4?_2o5d3Q8)Y=$2ISCD}W1{oU4NOwr mL8@yC(-a%UO^T1;7P4exn87T@Xg5N439|B&!X4a;C;tGJ(u89G literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$9.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient$9.class new file mode 100644 index 0000000000000000000000000000000000000000..72e3fe65ce266a2d9622b86f34bb01c31b90d52c GIT binary patch literal 1149 zcma)5+iuf95IvillVC_Fw{j^>AuWk}F@21JcnKgS3KUTkB;Gdm5^wA7Mz)iD7ZL@D z2R?ugK=3n&v6GMoS{h5<*_oZ0J!fY2`|q#c0PJJGfGjHUvQb114~lq*s)0=dTLx+j z#+dunK!gnIU9Q|fOV^%={;`bgPWU>|C&TEC2uFU@WXMIH46BbBYF!-+Y(C_UCu~Ot zt{!u{HI*%of<()gLM1Uzq>|B7hR)JK7vQM(7&0yG3WicwD)DM`(ig#7-uKC}($x<4 zdpwY_J~L)w+zena+e(R`dJ)^LDM|{kQ|8wQ|I+SYgQbeA1 z4Ok|&v16i$OD6Itm@u(xV9$h&U25ENeXBMY%JCJp&(**_=pP9uGC-ZT=QDB+@#?{} zNL?9HT|___|FLW>2ZG9=)qDmShKr)l=JTEC_oSFKy9=a;Q9#95&N63m_O#dEGo)*A z7uWvlNL_Zga)eJ0XzqAUZBU_Cn4>8)kSdqs?f@jIRrFF*^qaU$r&nm#AU#d8WNn{< zSv#jlSznO;m^hYbjne=>P^Q&P_9a}!b?rVKvE{$8Fq6;M}E5Dcr*v$qepe9oJ~LLbfc)_%rYb^<3c(dsZ@U literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaChromeClient.class new file mode 100644 index 0000000000000000000000000000000000000000..5939de395d305b7621b2ea50d6a6cc8e5702bc18 GIT binary patch literal 10293 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaInterface.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaInterface.class new file mode 100644 index 0000000000000000000000000000000000000000..43ed4ed6f35469682063977993439c11d3b2795e GIT binary patch literal 501 zcma)(%}N6?6ot>N{jse-b)o25gqe+lJ7J(8#X_NCvEn|>#A#|sN+whE)m-=hK9rc5 z>QoTHO%B|9`R+M4?;o#k04{LQ!hQ=q!cpd!bywWUm2@vdWA8+kD@W)DV`I~ZEg7GS zh#Q-j6^jOIov1vOIvz8fSR)hP)=p>_jY^3};RE3$6BTz29WbS4j6V_1{sAu--E_ks z90y^wku8_ex9gbDHu^?n8A}D>G8iwI_o|pqqp7n}r}2-`HRs9dxE9w_FUR@)i!i?o`~vJ~A%O3ku=% v?~_)egx<#f+H8|RsQHfr8g;@J>VVe|M~TI0B7OF(S?Vt z=)ilj%*U`0M>LeYFOm=9Tt1ZLqZmGpBaTnx#g1Vyj(y0;OEv}_#}aZeJW{ZntU}l1 zvb|=f^0u2x%?7^X=0+6a6MEIx89UI_=(|^R17}6gIR$4iug6^13+%x0+=9Y^8tbYJ zJ;c`a;+&(`6^>7OelBIN+L=c>mGS(n$8h7}{xDP${nClTiCy&5ZlL`oJELjQMubb+ z*KS4=$jM!-W~z#`>mINR1?`&zCY*xJl$fMiP-q@?Tqn4y5E(o*rw|?YvRa{i(sA`v zab;2a_eEJK^D=gR&h{O7FA1Z;BZoMS?S>;?%sDP0bguf&8p%yFoMY#m&*;=2+{Ln* z_by6hGIvp_WkOPnOTuLYcm6j7;<{tiWLukJOh3_?V!&h>s;=uANE$VcozE}YnaATE zTj5DCa!TrEXQY~JBHvyg^K&diI}22+r!dfvmaSSWP1H8_Jw|)E;JK;Wv(r;!zHe{v zG=B3*Mz5OIiNR60+b9n~z0LB!#Fk9jN>dOf(cjQ4oE*_0p!uBuG@dtO)zIrUA_Pp# zb7$;gf#r%0E=WleE5&@^1a{#uZwZAK&%LJ$#T6>FdG3^6mo9Y!g+qgrwwv`mC(C&^ zvQ&69B3_!El3MRhS_-Y6JE04K?`@dpySh-YbBuGTQM%PmnqFMi8TLd?E0sjdA!`Tr z*6Xfv*5SEhY@szL*pQ6!%;E50I=vG<$)e5IpB4!*ydzYaz2O_vP|)MK(`(xIoveP~ z=O;ZoYbe{_0KZTjDf)R5>gyGI^?}dE8mLm}>L5iKvnrEXmKZxKcQ!a-@tBHcCM~0x zeCb|`&w52aqi;Fp7AxJsGiFZD2#X2y<7fg$@M;1tFw_jx?I*YCDVSV^O`V(7&^4h&P6O0xRIqcT_Qk1?5+1 z3y#XnDm3Ju)jSwpecPs1>fB!SKAz`?gU++M;P^UQA!L?c!y*s()mXq$er3D(!EOS- zH0Xha{d@xs@YhV)LGI)geP$=g+@r!H(9tW*^SzTAECknMd`odx+?$fmp?>6ph2vbs z8K^M8H4!S{1YYA?Cr)CJ5;6V~5xS?7pI|*jSMnD`{zTggMCYHQ>5t^lGenZZ&(NGa z{S2|>(C{W&lACC)hB<;5&Cf846kFnT;ycTbZy_!bm{OiI{q}XMrNu*HZ z&`lHf?iYy94?joSm1uIPFM4_tiSH;5*^YAuX8A|eedF$YXi~w}O)`2+{B9;KWv4^Z zb(T5A(MrP3G0b^Nqtv>|`J(ahI!< z=^}SIt8awO8ir~?P8pC2)0o-rqb||kcJT2o?$K6py7rvqzl@8mEVpnZ%Z75Z$iJ>` gbZnyYDPqxY5smx|OKvp&UxaJ<;#7FRHw$zB0=dz|{Qv*} literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaPreferences.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaPreferences.class new file mode 100644 index 0000000000000000000000000000000000000000..970a574c8f7d59f7b5797d6af2b7921eca30aaae GIT binary patch literal 5602 zcma)A37AvW75?8$GRb6~EMZuJpil>yg%Cwt5Tp!@!c4<}GZYF|+c(K0L>_tLO9Eo+ zR<+{3TcLHS+ESDXZUMEm+664NtzB%bcC)M97hBufR{EctmzT^WP`-TMefQma?m6c_ z>wP)!&eP8VI8pP5a0Z+JvLVzV*NAz@%doK#n{Z(WW3X8^E(+j7AvD4X;=}U1ScXev zxHLrS%Vc)B3?C8dD+0JOgsbq;5U$3SAg&QU*UHOvAzY6eWVkVen{cxXx5&n=A>4-B zWw=9L?+oH&q8Pc?;jSiZ#kMAV9G{Tk?jY_7;a=Pq#3w_z9}fiapwNCQgim982%o`@ z5FWzAvbQsY&*G6Fb_KCpWIY+WDo_J?vY_{08a(*vT9(Q_L$aSw(4pqOlofR%6#$}FH%g$ z%p}b0!h9xanP*;@a||Wd$Rr&*os8MpSaFN=4fE2ObZ)+e`qs9U8hnfFBsCZrPiM^D z{DuM3Sz!!VTnWeRgkh~ToV2{Vi@w~tG&xU?+fFKG3>t}bW-MVlNt^f<6`#w?>QGv9 z*34C`6t&PWt~Fk*o2b)Zy2{t{AO*EngRWjtI5NftrM0qkrP=6+jfR!yCZ$&Gu93sq zn%bM)YO}lcW|!LRqRuHZ*J)WAMz^*V1t?b+-F)iswIgL{((8i5n*FZ!4)10seH&Z2B)XL;a@f#@zi7_}B>rCX*8`HVXbH(mK$IRM! zCqb|JjV#a64MtYXrJ*j}!oaKWM0d_~jGXOA^c&=2i$T2r9Ku^es9*6tD=kSdzB;I9 zN(kxb!kKh4fUjv7HT--4FY5R@z7fDTh2$kBbv%uT4d6RE zzKfT2d=K9b;1wM|z^gi5!w+@*2m=B9SXO?bOO*K{1)$vc*gpW){L{6fbs z@v8uSt>X>+M#pdQI}%xT$}%^aRsg@(@dx~ov6daQSmLq?$22nm{7J{3@fT7i9b=Q! z5gmWUn*sby$KUZ*0RPbOPwWriUpn5#zjgcv{|(?B9S50{7&%}h)~6hs0iLien+6(V z*+!B|<XQ&lKg&A;n#+x4tS zWjiU(hl5#6U`6JYT7A%PvZnVsww3`{ct=+?uwim*RJ^iz%?t8|#ZEeedr4DrA5l*7 zxSdI{a3#%z>eMZ@^raS>rA;UT<#h7k>_ItX$%OqsrN$Xo6|C z%1cvoMW{TfsQ%&dnbImVaGjCu<+VfIh-i9WM!gITPtSAXY7~L^vc&|z3rpNi#ibq& z^J^&**teQXQB&DGdhJoCr zN;eLhQSuOK)rSHotF*Hb*}Md!tpG=Er5?RAl$wOTKhAo zTRp0I59*(U?@@JbF-Q3>0*)o+6fEIPIPe6z(Zi>P_aN?an@>uiZD{X!68_;FTHwbt z#bI2L%H=?METwMJ(0QA2dG({7KVWqG6YzCBhK2$HGYSZ<8qT&AqtK? zoK1FQfAr~Xd5qbLrtr9kuYmE2po31EuyfK*B}Fu8XV8MF5M(km zGZ7{*6(%#-ThNJ_OoUSyZu6USQ3Lp8Y?Rh+1n5>+ozEoZ`?jaKS2 z3;j5q`kjSUTwSevAgE^H7!OsShpNv*)kjnkM`EQCDqinhR0n8{23m4O4OHTaeb6Jm zy*Q?TV|NujRmSCy_?4$dM*IqwN7TW9oU*HR*D!CLOI+t+EIlxhIvq#bw$r+^`LQvN z`Yb_;`lUTwvt3*gK`T65D?D5)$V0+*EIlu{q|BLE>*9KxJ94tK1}=#`e{^>d&eZT! zhTZsWm{94jeQ1>6d)Mw6<={V_|40EF2qHsc+H}q!fm}ck4nbrw2RW*;sRBTg=a^0p zK&J1^M3BsYd;`pi5peGtW z?a;e3qTxA*-W{Q^i2F`owf&u!#I5@=qFq)Cm^-9x-Gk|L=_PD?m(mHBF_$i9xx9jz zawYTZDz>Vt8Bts4*Bc93`v zUWALNP!12kLm_5e2p2&DapC!Acjxf!c)xwW_zK_&IyKB=qY4+B*0ij-ZOt8P?z-4^ zagR_Q8%3!1gpN$2qCm?$cx}{k!h+K2I6uyf6eGfF?@YWAfl7k?-`gBDKT;!k@-~%( zmCKM==t00~N)PzF5=%YEhXgtxxFXAB-i-*IX~Qtlxzu@JWESie$10XDWfmHh=83T- zUMQ{d9fE96vwmUzk!qIXV4C>1cAZm#vzJ7CpQWDC^3{0Mm*zzDCfc!Y3(4XOkY=-{YZy`yQ&Od02qw;R+T#EMeJ09V;%{gs1?cshqeA5f)_SfmRy=o6as8JqM4 y>m0L#imi!jxWQ^Y%Vs;b3c6C^S-x`NSwg4qEMtW`-Q-mXw{V@+X1dry6U`rwO5Fee literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaResourceApi.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaResourceApi.class new file mode 100644 index 0000000000000000000000000000000000000000..d2e3da5ae1f1b8e21d16c3fed5db57adf6e99cc0 GIT binary patch literal 11534 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaUriHelper.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaUriHelper.class new file mode 100644 index 0000000000000000000000000000000000000000..1c1e7877ab2e55172e040baffb109fd5d632dff3 GIT binary patch literal 2841 zcma)8X?GJ<7=ETnnKT{R8p~RQuvFWUHj21F5o|*WfskNR8j50_CYNL&oe7gk3b=s# zF7Arh4}R|#JrGdN@dx;$JU%yDOB#C2Il0Sw-}Slg``-EI-@pC_@C<(SVmCq^*oC8V z2zOut$GkX>hzBRUIEknSr#y(sW!%fd(_XxSNx4d>nDXF^7hRb4B8jtdHRHiKIln50 z*E(<>ugleJC*FYW#T-&9(jEvE7rfYpkOvt#XXRjcaS@kPUlkt6~UBcr!5MHs&i7z zNhZpxwG##XYw$-*N7xtil%T}ALxyQMhZUS0_+JuhFxA}{oL1ltS!w#;9W_i5E6&de zdrF_nk>ZP5DLpr>+lJiNh;Aoq6xR0njBOkjxxBFHvn!P@G1i4@*a|imvQ{ydj+caO z8)oC&LFro&fKBJUWMNeOqUa)--0n|xtNMLVaUZ?b4Q#=MA_C8J;v zpE1+499?Q5Jlh*K^#(aOrP~?djO7iQX)npFaWVb76?hX?(N2j8L!!Q+mMIMsM`ZG8 z*b7s`Qy9=Nh#?i0hCD8-ur(Aw5Y!8lJ{SzDC~7E4N_$#&^n(gInV7STLI$Q`0ar9! z#WfXgYIqBdhPQD|!NxlD4@0P6Ywcj9iuQ<3>@0I+IucGwpWab%UBeB$tKmJouV7~r zdrEgi#Udd!}qwUV6fSx zM_!wPo@US#Y-+CA@uHDS3!8Zzwr$Jy=c875Mp6zN?vZq(_Fm?Pb6hFkHpw}{6 zRoI4s)|Ip(hH86bO0u=tP9bSHSp^=M6uKc3yKkk6P*%4S;&M@#>`$^JHRg9RYd9ij z6bOWWV6as{4Gspgtwk`6bE0b$*di)~C{>CyW224m6?R2auO3uwwTz9|&|S|WQ#e81 z8|xyk+XWU{|H@EmZGEs&w>5UUs1}5Cl%>Q@vfQES$IAi_7Y^k*^>jK^OMeA{HLa}@ z)@U?j&F3w%(&7#*TduPmXQ#V5JQ9Oot~Ek$8;JHC9^0 zG=&|?>4k#eO{oKd6fg|$XZ z51A@;mF!o+`U!FDZAEA8R5G;A$LD}z!eoN*9a*l)#=SO^YTbbPJ&sk+`d)g`%t(%n zEs``E=ZC?e7N%A!SV5V}+SY=6O-ChAJ@v@y*8)F3e|GaxaA7O-P%d2uB~>9QSbSM+cR5QC*M}e^m@m z^D|8Ty0MSymCEW_8f@cgKc3@EGs-BrrJlv1J7~KDcc6^+TWEJL1$^tuPy;>>#~Zic z4fs0B@GeQVGCIkokKX;UO*2HFzA;U{t<>XMoNg>6Nuv&&hnFU77++a%=25*#wlD!jGE$n-A>~+rYfNA zM>{F|@I0kmJlVnr<3I(-#RiazIEc{-kc&7((A#Je=p^MZ|3@NtnWQn2+AxmKIeSSy Kk5BL!I{pJNCKmkw literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$1.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$1.class new file mode 100644 index 0000000000000000000000000000000000000000..1d927a883307df01867e2a7fe8e5f3a78f2d1e26 GIT binary patch literal 941 zcma)5O>fgc5Ph336URWH1=<3orD;i0go)H!5E4WnRSG>2NY5L4l`NQDwBDxuTS!nO z4*URq6fo;JRFFfkWY6r(+qZ9L#y@_3`wpOkhgFnu*GC1LK5pZlk1cF_xbI1#6%`9~g2L>Ork>nRU=GkYvXLn%(X1b-rxv`-oKn*V`s4H-&39Ser5eW}FJ z$%m0JZ}=#o$o0OCcrxThx^*5bIXMhq2o9AJrkC(E6%^TBeq5tN0;^iR7LkxsI^m$% z=PEW@#&jWNg|c)ZvS+rtkT}fpU8mT~z-N|WeE~M#PnD3_4u-V_P|n5R5A=zN#7pV! zyYhE2AHCyKPIY;qqC}@sjb8~n(Xod{fL-hb@Ng+W)p-xl^w0{>#y<6FX`31yhV6eZ z{@iFDM?AH8bqryaGLdN4?!5g2VJ+#TW)z#QPPMVH7qQJ|>rWw0#pu1XA?=&zsWTgM zNsCz;2I6{~3iE7CT^d+J=P;}irK?hya5WBR(Jl>dnMRpLq+WM5BCkMi6+R73jl2U| zyNKW3{{q(jio&N16VSIp7~mH!(>KU`A6IaVRwMx{Il~dzqC>PlgPo&zj?(c3hws=~ t0X0_4c(!KPoX7F5;zq_D;3jSnx`;JmD_|WPWJ~l9-a(x_r?^a(p5H0p?8*QD literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$2.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$2.class new file mode 100644 index 0000000000000000000000000000000000000000..217cd092f0d7434c5c59497a27c98b9c07321dad GIT binary patch literal 1282 zcma)6ZBG+H5Pp`HUMUCEf(TLTAw}8(J-~NRBx$N?QfyL6P4v_Cy3)hrmh9b?zhHcc zzr_U5_`#2U@F)4fI9E!rDM`8HW@cw6&oetSyTAYb_z7SIn?q2M3dCF>?!+*H`50~^ z9YrRJYzzxn9HRA76uB65EGt-1u&UrLL!@QcseR5cTM}|tHx3N5$#ql6hG-dj{#3u> z^_s;G*BO)`+?O^(qO@mFgl#yx`nD%6XP34kUej_@%Va#U9Lw8ac$2;a?qx!H*fKSS za9%Vh_py@Y@R$C6oy)3Gx5<+z3DdA^hO~lp#~BW?V*rC%bQ~`8w&A**JahdMNUhTG zLeh6grUUBOw(zCNpIZUlcz2<4L9&!q!7**&Qfaoh*Axu}_f*`+0~OGFoatG@(LAAf z6HqT`8RxELnWy(9HHDD|-GiGvb_Qza?v0`OA#1p}i-%wK@fi`wpAi%9df z#T`0DrvCt(hSCtsU%=npq%+hp;Z(TEtrl+-q!f~2GhH&Ah7?vqKjigymZzUxtzvJM zy`D@B8r|>_n&44{;_+aF0Max?ZB27UPr?BG6SzuIlVoksIvjYi3&&vD#bXR)myQw2 zena?cJNg>Q2t|Xv#}wIWU=zYLZjffUiDU=M!eDz(&mLjm1cQl4Livs;t=JKUeqp*} z1>5mIi5Th735L&UCJ6xS0~GcVqwEu=*k|O}m;Y$>4s8gxh1$y0e$sB{K_k%ZMxG2xQu}7SJ!u()0uZo^VW{+MAgfiynUSM0 zWTx0+Lf1mttSK#6WoQo*#V}S{*DA3p&wcBuO6*4=kEEBPn)cL9-=ON*&-=LPis;Os6l2O+TWh1oi5 zPJW5G6mHu13b#@y+L*`Jl*f_k$V>@z?N(V_Syx_6hIglSL?CeP$ZTwPTeE~48TASD zW%uy76l*dueZO(NkEPF2R(9TuIxAd>mtyHXTGrAdpB?+UZ6Z31npDxUFTf76e@6F8a8xiT#4$S?B+tQ2-un6CGrdA@2C*kX9c zUtZHnmidnFWoC!w>0Ajz{A6@e$X#ge>M{}m=&6#1r%)Q6T4{Ldh+m&3J_9(#Q-h4= zIZo0KIr%z-bGnWuXRMBdbHb{_at4~~Xm)-_@>S#HY1$-DLOjJ8#K6&O?J^AveZYb zjEWC_fFEVqvjm7Q1XH!sJ(Hf(-KWp)?>|3(0a(U^KBSN{%dAA)(`%36RZIr=JkcaIERh}_pGF3S6DX&I zLcivo(d-FrAB8dW*G0J1(1O>VDMfQ4-0$f565ko8wU_RIeZV>L9phsX z6SzQ@;UcEmh!sLK|7G2;U_a2i51WDf#6Hd>jFY6t`i8z^-~l8F<0D4dCrq=?9SO4S b1W8;X$OJW-C2P^gY6j=YOHry6S^E72RlP-i literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$ActivityResult.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebView$ActivityResult.class new file mode 100644 index 0000000000000000000000000000000000000000..3570bc61b90f0238638a8e08e4b649684be85358 GIT binary patch literal 757 zcma)4&2G~`7@T$7xDBQaEiFxGp``(ek?O(~gg}vyEJYvzO3xc-m27a=uy%rYEDjM; z4}E|>RMlD2OOa4Gc)p(<&CY)QE-uf`0ldJ|71XiYK!67>d+1=#!G3^)03CtAs_#=( zlma3Vs9RM`GZxF*r1_~fBZ2LnG((%~VVvfsRHlrRD!d}S9P6TUEO5}v?I@PtWI9%) z*o#KOFtFHoANx@b>UO_(}4wi=Xuc{BAx}0&6{O)Q9QmK-n*Hkg>Dg z%Tt;4rPZ#!Zu-us!0NlS)H7ZF{B-@yFfm5iZYGOD@%-gtTb-K{d{vDTtdIhAU5!Sd z@j0K`RK3^E(#Fk698Kg*hPaK@5NmiGVi_wT8V+tD4DdwYc;Ptz@*&W4s&OXGDE>H@ zsFXjkcIYOxzfcQ%+=ze+*f<23=%~df}P6vGDjQyD|1?Ez!sMvkky9lT~Fos;eP-RIB zWoq46stc8$k<6_d*-FX&rF~1;P}6MtM*W_^GMO;r)aZ&_sfu2nQ^}n+x~VcFXZ1+V zD0{EH@YML_Z6MHO zB-skK^_@=;AAW>ee1##|f06|pHuxLmE1VX?hfN{e~a!E!eGjV1TzQAH;{!BIPT=N{Pfqm7NdX!qCkJSxoWhM$eew`qdRle12?ACND|ANl2v`Tin{?MvMJGGAU{P=Df+ulnU{JnVITe}lig8IW(ux0y)q1msWU z&jPdpq60O1*Dv4m%lCQZ4|v6&^W_(O`K4ce$m4(IlOF}-ujOw7^s4-rTYk$l{Dk{_ z>X*Oc`|ktt5Au(G`6r&|&wlwCPyH9Z{M9f2#&Y_1X7Kae_aA=wPX^>)e)(^|{M;}9 z!vy#OpA=zYCHzXFMJaB{^Q(M*DS)sjpHKPysxUyGsQ~0b74a8?yA2AcVpYPI!2vZy z1^sF$c%p{+)o}id_Yrj;e-T5_9qZ|c##ct-5i|*!RG&z8R7AQXZJlOCTO!$> z0MM(weK4q?JJORf+Xac^1^JU^n;Grp!ISGF@%CgQ+K!P}Bc85UoJ>U8+ajrSqumLk zefG41rsi6#+FF!>Om2v@nHUl1jhdUPV^Pc~X!-#LtutHKI$bf)XzNTSy3Fj*vI7jQ z_VmQa;urv5lZ-V-yUaunmKAk^hJe%Qm1exBwilrAC$ujIJzA5|_71${q@In?V%-N* z7j;$lq|%8lhLpLPr5Phx!HwuM)YGRr5{tD)+BW*sEQpaiHrp=fFlUZUX6wdix&n0Y z;xlF7AciAprV>5LHWR`uXxag217Xf~#JC|*W=%X2Th|#)o3UsL)ES>^wDX+@nVSa; zDr6d)Ol1JmoisO?Ni*KYB7PuXR=XWB@0jXU(3SN~)s3~a4eOUSR;{gTZdqSl+t6Iw z2>#bcwt#!9Bgse?rk(E6iTRbTSb}!b>NCaL6%!XMh{mJoMS{kbIis>t4XsTBpZU|* z3d&=xgyz;q<7PuoSF4$9jPi^ z6C7@fq}gngHul8R(4Mu?R1~zSipLY_NID8zC}@PoP`P73jidf=a2(HolyoPfy;vLO zXj2NN7dYD>)Wv&q05RU7NW_7yqB)X;%s^QHOnxsLY=vN`2qM6eBIuI?nHSfbeL3qb zb2a|}9lgpu-(&3Sp^Q1lxvH3J)&qaF<amXEO_2B-H zGPnCE$(HV{qRi>ncR?<=Ex*L`Z((O9ivR!Mz(K&83!4LT;lN+_!=nb-7ui36#NW_d&2ZeAtE0H#9%+{U`<|f;zp&V31 zHk#mfUoBmAa7uHau**9kU>jnu4e##kO1G?Dkxm`zhI8RGq{0UDEC;W2a6g;)DDc^e0GEkp|kUi zm?yWgXVkLjd>1vCXx#zE21ACpvAWZ2+lbi3o~I!J;EE8sck@a* zj3`OOp@E55thy7(vj+Og>hK?)Ey>h25 zJ1CptHzZ(mkePd(ijn9x<5^{aAhpHJNYX(9d9#&>^iSa#R7AJ~5%8w%cGX}YtvHW| zeRXMQ_sm6+gPf4%w+MQ_Ithf5X)pk3z<>n?woD(`1TM#sWw9GIH$)(0wjLI=f_9u5 zxEXLFRk2t%0wK{2X-~va_NYm0iX&hzt8+Nf%b7C1SZcziUPZgQ1kLQ*BO34SNq6b+ zrJ|0XtpLQXbzqIcw$5m*-7-49jixTJAhtI-yB9RF?`+O`&|wYN8bCM<)_!qMI-Q6^ zN09urHz$_EEajKgX@liYpe};EA6N!jqw#jDD=1Q?KZ6836v-y~>lTK>!gokCwHOLu zjabZb#sOO@$6|S9bxeXHSRl}IHJ4`aw$U`Z*`#SRWmwlbaEszV1B7AS8~)(hyNZYjzg({Fx^%Z_P^o({4U z!?-5Xt2Q|L8nCC-6^dfEKyD#LP@Rjb7D$$(`8h!KI_q4O7^X}f&j12tEvv4vu}?#o z<4ozSvNW0KVS`cJ3DNR`1Oahhn*guHeHeFGQL~ACN1ue=RX9&+#0h~1(kqyX^qTE; zx@Osyov)y4i^VQ>jY%`>i^jnbI-ute29%$4;AYiN0+s`^UW#FPFip1Rgu+ekD8Ne3S6O>3d05uH~|nLT^9pyfHeX}>bffkH19{cH_WZpMuM1&AXNp`xr5 zXwv8*DF91`_MLPVTUtYuiy4MkCXR(;(x%t(Y>55&L(~ux#Uw)i^W$Ep?p~_7>lV2LrfKi z;yhB`vcHN-|Hkiu7h-LR0t)j z5NoU1J}cDR8BK*YMPsp0Dv^kXTFns4b~K4^J~hu!N2;Tc1MD9IM^1dI(oplog@#(7 z78+u`T4adx#QBCeN1SV@qZL?mrMSuvU&lq}%K~%}rx>bAEjCoOc+(IU@You@)T$+h zT8cKcOuXq+b%t7@>J7D0H6WGGCZMiugh<)>e*iA6A<|pZ(*??vxMHNYIecoBp;oJ7 z4b`Zce5%<{Ys5IXO1GO8do1pOW94LbW?u@1K&YhUl|rCYyV)CUGecb{1BY6-RE7+- zR;@GCajL~o$E%}!>I6fbB<6sR%bKfw>SRN$SEnHIb(gckMMFhYt53BVs$D^yJi?!| z@*rr{Ix`eWnhZlE)P)LeG9H4fPN7l|N^A&KS=$&hLYqvBukG3DWe9+T=FB?G20ayu z#_@V2O8+iQ`>SLin5;>_B8SqQX2>RSXhQ@RpdG8EJ43CJc0gs-KM+NP22RLKV@ zEqYcW9Eu}wNrpO6o-pH;p)3@AhlIM!NIV4yz=&unJ}sTaH57?&>4NzNknXZyT1OGI z<^T}vuln+(K+H1K1{U28zI3XnPn~M0jp{I1&}=QnP%+izQ*lEjSX#Qd=V{^_hDs`I z#ib3^!&dPu=(g(R=1tsTGheo-(+zb7x1GtaXDOJ=v007i>!`9Nn{xXz3;-t#vp8-_ z#Aj8nYFJXYbWLMbGxqA%S1+q-SXx_SsIxJ*m@cqgcmSP8F2e!C6d1T=>KsFztIjjj z`QlAMH7$uAaIu%A(+r)OXq^~pPJ~cdgJ{M>R%s`M;UTBKGcnY%YE5Wa)!N$7lB&A; z+M0>bqzl-h9kPF;;|)s~h6|Cs?Z3ATu2p;yRFR`+U7J~r?7XY5#%D(?sfng^kt!5v z_oTFr>4RCdcF{s8(8DI!D(Gk>QXeZ%v(t|EbvzqJm9U&#p_s1E{A~O>3XCvixw>k z+0}qDgq_$F{u)~gFX(z~Qnn-r?IFL5PF7be& zZW3jNxQ$77yZ9zbqdC~>sfaMVHyi2}b*rInV-Ri^_hKUTO+($mM4!MjLsGd&U;)w! zVDOK($&q6l;&EOI&q@I;ZD>tnJ*;{<0ps7wA-64%(KI_RcKa~-o4A4& z;=RvVA=GhnHOLy&%3Dk@!%+musG!dZm0`Yx90MSV8Ijw}xE{HmfmvHuyADVTFzHT1 zeM{{C^_Urkx{Hn8x7FQ-x<~Ca)V=CHLw!elgcz&;68kMzpzfl}U>a+7ODNZc43SXx z8)}yVa~@O=`P6PhWz-%+?Ntx^)FX!4rygZ544pa3qcgUe&DwyVrv{Z+UBTxxx@=l+ z0-3SdjwIg7cBf58kUsB!Gq$JO8EJ^;#S4b`BO)B}Gx4sW9#h|ifay$sy_M=4>T&fb zyjYeFI%_&`DZr1CIm<{$yF2J9D-7a5Y5SUfJ>4-j?=P&Un`PDL9kDseM5ZThT4+%BtVeJMM5 z>frnjS7Y`I)yp7_dPV&N{)eHmP8&HnpP(6*!uQ0JW(RDSsYwooY>0OBB=tTSG8gMK z4@=0a?D!JuHADPLd}OHC)f+wqwBJ&18|oePQ=j^oq2A^2DcFpNmhEPQtz)~nnMWU| z-h;Vfqlr2hcd)A|mVr%GqIraO97;K%+33z6hO%{Ld9cbEAr6%c^*(d{D6zm$AE=*u ztf^LU?xG7LhNu-w4fPB4p`m`onbAkgrr@$Dm+bpa_-pkWL;Oqp8=;RK-~fNFVpz0* z!`cLkzsYXI@QFV4F*;{$%ccV#BVm8_TWm1p@M_goTw<^4!39po-hpIJveSI+!_Nc;mzzDxfR3yA9F3* z7c2%pfY`aoOmfovrF$**CIAl`oCQf&km?g12wfpsU$R+~ouCc}c5(_8n+=@uh+=;= znvO)i$bJDeN?mI7`Jy4_BAz~VSerdP62wf}s98wBd|{3f z6f5l2n^27bRk#`sl*i!1TI^h4Cq8CHkc%TpcbnX%!; zyK0&Jj@7yPzZ`ZJ3wSr-%lb4Uv|NRRd>!l}BEza4ocx1z;nL9-Y~5x#GjM+UKw4F- zBauXL0Cn&Z>xi1CrJ!L|TI z2uJtLEvsvJE6sI4x^je73&B)t3r5f}IkuBd7%;}Wos_LbSTkTcN2+xd8}%jxf-9>U z)-0*2ZeG*K$Nvg+DFp2^bFAi_yHC*yQ~T2is|h^Lik(K&)(PkjW*wDfUKW5U_OV^0 zOzu-t&5HGP4b6bprAT&iKbwIFQU$$p;(o_&aKrFwRMc3>|{)tXS1zz$7Ujo!9p<>QvsIRCr} z{tTg}b^K&aoX-QNaF|CIpOBaxNVK#S9hs$NKf{PQ*`By(YHVu?q|jayMTrrID_o>( z2G!X#iY6+!!VdBnx{v)1g0g|p$9Y&67#}|1;}{4=E!${!>kEc;0O$~pg~$S)^9azS z{^$+tg>AVFu?U~Q8jZ!5nu(Zwbg3^KY;$T7T}>RMbhrQy?>ojpgs}tls`)(k%E)GG zqbsj$Ijb)tnf>O{BHQ9l0nFDRrLF2fK9`l;LU z(hNK^KA;PS49j^kuC8a5=Lw>MMk z;7s~;vXw^fB7@l=M>4JVJbB}!|BnIcS1s*h`I#pArvrYRZb+GU-OucZBmUb^F-zLq z6j*;CVrPfe<%+cWM&tAAJo7upf|$mMgIOWh;DcDyGc3ywtT-&I9T89PgrEzXD68UY zqRpLrOcP}|uMO-2av+*Qz}I1&NgtbopUzP)c&KO!Y}XCEqs!4;VOu1=G{HN;?0T|h zRr^Al@ldl$@9H-21JTLlXnV<& z_Y<{)e73q-fg3C#-mP#mn-hJ>ahI%Gd9bvb*fH7kD#`NBK1~D*uT=!QnK=mNnlbnA z5l2i-u-trTgX8LzIG5IpL(+PNezVW_h6OegPyvSpWCv0eZ?^_6bPaBH9S;&&$#W>5 z^=iy)eNxJ2PlyWJz?obe28_JXM{eRRKmyNR_RmU z*yfM-0NyMSG!X7dAU>X|4+Zg|P0*!mI(}cJpq|jHBu+K=qH%0rJ7f{c-f;$mg>8v0 z=o!uwAk4$TEc-x|t}ODb{F4`dBF>twkENmFgNN)FoH=vOJO$lCnH#Yn+R4J674m@* z3p)!IA?IM^ec)y*jfY^!-L36Cg$7uL; zRTUVGf*v-wnd$>4>U$7t+yOgSLA#DDhUelTKn*71?g=K8?AlovS%+7Hqa0dzD=dxx zTOTpp2T56r;LE2z6*S-Fl+)8apyf2_qM@B_ViFm(C{O3@g8&xr&A+mrE* z<^)8Z;lP0qnj_&%Axiz#@*2_F57vbw%w_gdd^1POQI!$SHU z=Y{k;jvVQCoI29)IHRNAv1_95DAMXX4&mrKju`1XP8s1&yiuy(ao`B|QCzXb{YXHv zOw{4J9B)UH0`x?_aJkq+au*(@Sb=LmH*cl_+9K-lKEmoIR*D9^VSrdARugh`Om?h2 z*{PUJ;oI17`HVfJ!uu$%We?@=rh>5AjU@_qliyuo1o1E3&%_FgX$XGrK7tx)44tJ{ z3t96xtBti+!`z}#GyxV~x0#eiqKESEKhZd>J8lmZ9@N6;kq-+8vG7PNJeJPa3x}d{)aJUI9 zhb)Md_R#p< zAQYa0q2R;}O$zU!$@n*grA29ZTml&(x&lnQl1k|7pwQKz&^JJ#tu%$Mp)g%bv*|iI zg081Z+D`R!1GUqQw25w}^XV44m~N%7(rucWjTV{?H80~+fRJUNE+SAuR*1_)E7Xvs z`7+Ta+O=3*#;5o+Cobcod|*3&W%cq26VHY{N1NCH>Q6?C6dm}7V+$ZOtJ@V=nP*?j zxIRM*gHwZt?8Uwa6XFT{qMUk(RYM{FZMZgUyLdG+Oa89I_LN0mQ7l^L2plokXR<~>G>TGRt{bW?_oS@{4} zH3X;bqs0)O>R?TVYG>kKhL-H5rRyG`WrK@urwQm3tjo~yZ8U5~ImWMOQF(i*9uurw zw}WP{1YuTj{~a`ipO3YkNAYu$^=$C-8h$PZsB8J6XD_*feC2!TI3{U^T7t*p!wDHW zaV3L&Qu&Mwoos)~(E5g%578<4XK$kt25jhUFj9Lc!kt>VdmCTc%ZHJfp$=~CBF55R#YFn2IE4N! zD(G`Dm;NIb(iivzf4*2J{95X|VQY@2D*Q&L3-VV@3q>3*NdZ2;NQiEN`|)OR9*zVH z4tFL;FULv+Y%3-Bw5mPVarRteS$vCcr$PH@vz~Ly{rl*2{d9&qdokNHQ3^ChQxM^c z>(|FRtBkc*$>U?L_9|=}**eO+o&6v^M9*Q_J!#J&`JAsk@+82=BPTO_LvAMn^geSh zowaTk^yF;z3uE@sIl*%?be?O_bYOtk$S=x4?Ft$q4y8#rpvvG{OHHOH`ssP1(dNkEkc*?b3C981nIxTOE!B{>JFtENJNsl?Tty&;{(Rf){4!qHR>fZtCJ4a2L3L#U)S>GC+vcf?^GgMwrCW zi7R;_hxj3}6?)CYzgk>lM|LM;EyyelD}M$I-Ak8X=KZZ;LQOlUSZt)BqD!w}MUlgt z6^7X>U_NmzLO3}vLc;1ej%efR365dGFLhDU!7&V2fjG^BiqBcd=b(ZUjn-sh6zmE| zS7*Au@vHEQpjB<~vaEx=9OmF_W8scC=DGrsF(N}(hS^K`=H`WiR|UVGp{w`OH|FN= zqpdCBnGnTmDhu|}wJqV{`7?*-l@{!w>neR1D0B?5kFIY)jK=-8WoWyL!5nB3i7kj_ z&p=Ld7EKjrBRn{V4iy*BVNm>|#6`43TtbZ?Mw_^k&Jg!#Os&xAOb6359g?0Ywuv&Z z>oBSl+mR$FI*O{r4IpzKEup#MMm*)i)rG}P;%3;@He^h<;0eKtz%fvpLoskI0TFNJI0b0l;^Ju8kq2Qz9-@%~;S4gI zqr}4=j#WB%RC+jejSb61fRcr8UUsc=IP_b$QNa$H2ykx8*I`R}Q%m01y>vUml5d8C zcLeXu(6{<&fCb3Ykjod~sa^z;e*%KM>XFfT4j}U!g3hyK6u{u@rVY~3AP*ajLBM(t za;hDWm%ChyEgSbHY|&frN^k20EQ>kFUO?~}P7S$`2?cey$f;WKHB?F;UzBb~B_C#ht8a`srJEVuDT- zJMff8qcG21;@c1lA?}6|X z*;Hb_67Xu*HYB}!=z+YQYNxY==9L_WCC1~A`%R!ha-v5dN*saMBlcR+k+>FI`kM_0%AKpWc zROTa8-&a`>e6+M6Lyy6sY@?B-`K1LQ-2`s>ZiXI55>Ui#8G2$J+AYh*g8982G@&xz zUFk`CCFB~V`FrUH9MGMDc=8@Zw^kOpoPyxMY#JvIqlxlxnktW^>2f|Tl#B2u)sCiW zxtLCoOYxWWmeFal4u2YNIbAL5X}fHoyX3KSk6cCf%GLCYY}B-5bGQ+4?Ze^`NbzYj zPwW$qf{ORT(%8AHxuE(DQ=t-VP zgXKy1gK;O*2zd&Pml05EB=+_wQg*Ob428J`HWp&|AR6A_yq>wneiHy|axf znUtW-6!i7O?)-G?jTjL88M=h|6;(Km`Mc=WtSSDUOYwJI17a!5HIy%}gC)EkVzP~b z@+OewW(vt$K$dSpdG4Tcc@N046H0V16zDr3&HdCUAEe{tLv*s-4TZ9Nu4Ugk9JD(e zv^yNMaa7tyo6}`Rd;OSua3!RVCwQ>^68H6kb-VV_ z>XvLp;^(juu=&4$mDoeSd>q5A+)F2W@-do%N=TV}lIF>$fX*{iBY&tlX@S4q0e`&% z{(AAc)@C8z5O3OE%#9s=SnNaB@@oesU!nr}vYvKeVU;J#?ZDnZG-)}>Bxu3Zm{K16 zRfay=4lgr!)L1OEgJY&&>!v_>a49#rYwJKnzD9-ebs8$)gmAw_ljS=e^rkrIO%ZR| zNTh?)Qo^Trn*gSv}nQ48VsfbjczA*;md4VJUg?-TE6I&yWHiIBU* z`ct?-iwLt>Q?O)#)&o~?bq*yz)T>$HPl1J2P89GH2V3Nh!F(L4aO9D-QvGNB*uyk$ z)M4Qu#CwncE5qRX^nBXir!CsUL&%e+N6yldo$a)_ZXQDQQ zgMZ}ZIc>D55MU}~=ufyM*n->TvJCwh5jILQS&jXR<=6j;8C8;XI7Fy?L|$Py5N3I#f?% zNv@my|HhH~8O&jjRC=O4E%W&KQ$5SC_0<9(r_6usu;)pzhm(L6p#DGVf!seAszu|* z-cAe3p~nAWCz_#ud!ww+!3M;F|G_Qz1uh(kF<&6!7b>yii>F-bXfamRl&@+iplWG| zT1unTGMb?3s0Q!L)d~$Trw^lOhWM@c1U6&>vQaJtApWLB;!`_mSYgvMA9?BT#P5M( z0Hwu0;48<)__31BvuA-22S#fxgy8-EwQ|POv<#l_-wojm4$|Z~k~I_oH4p%XHUge6 z5{*vb`f?pgT;L6_55Yzasbhg#BNeG8aK9OUJQpPnwU!Q7>mX;xQM0m29UMRnqhmBy zibhkV_!IDBYq{3J>R21AB3hy8z*zlRd}d>{8(4Aws^HY2LUF|sB8fmCFymp7CukSf z3*N*YjmQUz1y2ZH!_4vrgg+w+!-H`R%v2dsG&3U%mpQrwpw?5NiqK%yN+VPojZ_^p zR&_#YHqvwz!ygk*&^(o-1u8|ysI+F5WxuN&@vahoK}5sySS9|7ElEk!ksJO^{2d?* z{&km)!qv7iEn*Y~Wl?yB@^&#Q3}vwmdwn^#WJF0Af#jRvheWL^Hgg=KSsdFi;&V#a_Pe-bYXra1T!)!U(MK;Wnu#3p>u}c2a5uADa4lFn)1ZC|g z6Ahlyth&;pVA*_7@UL5JBwK+b8{1K+MTo)Jq8KWM*r;+TXNDVm>-0=*g}u54vU45C zf4!dDvaX{X@{SUpBe2FsHnPC~K<-&CzJNisTwop6V!045T`Ws*lZRKrnM_DwN18%P ztvVR0%~MWaE0yFpo-<~z!J6P=VJ&v6hboT2;=i4cWAKpvgYOtP7=PZ}C;d4Fi++QV zdbtKKUl!`kX}=6OLN`s@0%XbiM6gB5!9(_lp$`hZ3oZ0si$(yMo0LVsQc44bI-=uI zUl@U{{*kD^m*PGeZP();|97o*!@i^SU$=F`-@%?K<`)#=k6BL@OAul$fz~WPrWAij Pew8{AQu<5bMb6L}>TDYEl*cm>#X6hl6CMqg^_>`xr1&sM zq)OfBf!}d@r@oN5lEV8$JoDdQWb7j zZ@M-*HXeG|N0-6QQ)vvO9p!~iZA2ap&?6%^_OU^;eWM*ETur0b<6{vQWW*YJGgoTq zPPj4a-=Gf|!cA?XM4KB5(9U_9n&ZH*cQ!vU@1Dubu$Ah(I23u#r<78&HC%geRAdxM z{}i$`svnN%tUGk_DPu6-H%ZYyQK8$%1wsSr9@E$$ZoBgdto;R*kL8?;^sLbw;5#nS z(<^%ymvMzg%tXIpcm}I{7qk~(3s?(OgL6UcGwd~!TWb6u)t{%>f)$&E9pbFuI&M&{ SlGaU}r!FAOqiQZ^S^fa>o%Un^ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebViewClient$1.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/CordovaWebViewClient$1.class new file mode 100644 index 0000000000000000000000000000000000000000..19b98db528cc0c6d94436f73aaa3a42c135adf33 GIT binary patch literal 1260 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 Butxv@ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/DirectoryManager.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/DirectoryManager.class new file mode 100644 index 0000000000000000000000000000000000000000..84e634ffac3ec2e92d0db55a48d36cf41793bd82 GIT binary patch literal 2643 zcma)8SyLQU6#g29+0rbTj6(=n2w5B;$(V!~60O?r9=iP1zO zYSb#L;)|rz@{Jc$r7wgsRsH~fl=_|SW(bf}IaS={+_QZ5JLlZy?|=UM3&2r)7sq~# z#jy_`L@^%61$-FC1TMzWh)W{AEUPObyBftc*?c5oEsDvSe}i8H`8XO-kU^K>dJUcP z7lL@4ieOp{3lSJ`G)cH7+>n708Zi@v8AlOT6t>K>BD@)a6G2HqBzI=;+E{i_K_YiU zo6|C;W=&;AUB|Gdx)jv*+E&TcEO%Tp%X$>9f^fHC8SXm@s?%-b3PQbhL03?pGc0|i zT%6RMF>TVMB$2c8nmMjHhU^1j$elJA^+3*crZU>BmY>!$dD|)2jNE59dfv62+ryfr zP3aE9*SUJh9WYG2f8Hp$G<+q!8D-l=qL|g(Y3lo@hMf^3I*3^Mt+U=ynAdR2bfJj4 zr4tIBL%WJz^eI3DWfgO{ z6~VlU+qk3RW876SfI$_Xpijl8xXYp{+6{8C*9IC$ga z4O6M%^_$;>?5rWS5{21~-56&hJ8tQMA+JqXo1N7ymK|GQjm%ZQn?ylc+41$_da`7j zWmor+HLg;&p@o=v4}E@yT#a~-))oqSr9ns?F%)MChEu{`el+&;lb~P+4&Wf?SGlV~ znl-IRiF53rB*U47j+*wTQ2y{#4si^7!d4vSTJ;rhgvvk+ukkzP8$Y7M5M}8VR4rm} zd!l+7p~u+1f|}t&%LuoxATn}z8PV<~)Kqsj|3=*^i2vP$0eY&ZuWdMnoj6X&orHXn zVBhrOcA|!7bv!*ztDW3+a#c;eYMj999;&pb586}(vKZc=y^rrw*j4dlrvr9YlVbslaSSl450<5$l(ZKp7Wr# z5R!2D7GcR}xPxGX^Dwo#&`lU|c@_d#C2EAJx91reCdm8NT*opJ3t5ia7EXpzp%x>F zWN{5f!ejXoxxY*ZSCGP0FKoLf-$RBD(p`-5ckv#B)boFWtQR&#X%AN+&V14W00jc7 zqD6|loNfThJM-jMBHOm?i0uZ zmcv4Yh^-7D1tJ$af%iQyvKsO-A#(pT#@w9_VEsZ^qJLh=k&1wbW6$C7DrJ{|+RcIJ z_Q<-W0xq|ND5ZNPgVD!`a%#Q6Vb>aFztq2HoJS<_2PWf3Cg&$2{29ae)x)3iQ6NW& Z-1RJL>o_r1<4mwW$C)_!C#^XO{0BcaR(${f literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/DroidGap.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/DroidGap.class new file mode 100644 index 0000000000000000000000000000000000000000..4d5a42189e14d211c69998407a219d01ff63e2f6 GIT binary patch literal 389 zcmaJ-%Sr<=6g`x2m^u6C24Y30{+QqCJ>BGp#=IVX?0sKrpi9Z zY01hUHMuM^X{qJkV&LYq6gWtYoh7o8`CKKrv4v@5GO>n=8(9qn;(JruTwPOJsP|)> zKgve3IZ>5Wxpb-!*t@H>qlL<7N!(_nwQZ4;7G>RIxeGwdQjD6s#}2m;4{ zxZ|%uN4cYh+!K!A@yE1F@aCe79cIaj1L4^V#4`&XBE}BOz#-NcyQ_DIb;QhkY%qGP N_V@-i`Lxk};1eudTao|( literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/ExifHelper.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/ExifHelper.class new file mode 100644 index 0000000000000000000000000000000000000000..d93d0563c6cd6462bae47ed235b4ffac927ce0fa GIT binary patch literal 3465 zcma)8TW}j^89l!xOKW*8*^=Wnb?!GiPExg{1=@s`G_e~ua%}97G-;u%rM0|?ysNHO zaavj$+NKv08d?IqLpoDtN->lSB`ufXg&COPi8r2j;|X{tPr&*9-)ku}li@+<(>eNY z`+w*AR)6~UuYU*NcKk4dJ5cW8w~Bx(FegwIm>2K_P6(V7s0l0x_yU1IUEnc+P@o|Y z2{Z*x2`mbnPUG!7U#Xlz2D)pmpLfq`D0#>)PTeWbyTx)4RsyC&wmjh0m?iFKmqVAgH@B%hTSvTx$J^NJ`+>;_ zFJqwX(OPqM+jtNMZF~lI+PF*LvjU$J_`JZ~0`~~)7T6>31%Z17?i2W;z+Qp-1@;N- z7Z?>76LeZ8!r%=IAZMAT3C2u@ZM=rpdHLdRQzG{0wG}hATrp$URLlcYGi?>q z#!L-RXs;O3xJFoCZER)qN{P^a@_SrBredgEr(&qek(bLdH$F2tQ+M6UH0#5!G8@SW zQ#}*Q)pLy}?4xbfW8)3HY2z&%Oyg}E@8Act%Iz$r8+w~oYBit9*%NL#QYdK23yR~D zD=wDmcB8!!`_pVQVnJ=YUJbN)XQh+bbZXnYq3g{1^falaY{NO_uFT|R^tFyE&7kUr z%zE7k8!Sv7`?^&*j*V>RckmUm3LRo!e(Mki>qrypNFVD+E9*!%>qtZENKflXTkA+? z>qv9!NPp`{i|a_2>qw*PNU!TiyX#2D>qyhocaIq}qrjvVZctiqRkW7-~fQ z5*-2wfuumEKuRDjUu@vH^VxL!`Oji9Q9S~ zLK#KO<2D@P%C>nrj+r7;_!6f1#PZ~$+_QtRXXH1y>DZ2saWhZXI#@>kcsCcgM=vyB z1}`tfX_(>lDsBuer0`{aj@)qZwx>3W@8jb8|L?_*#yL|y65I^9Ix_MRR^?Y;!7Y+E zO$Ied7_vr_q#`WCMiSKYmzo(gC>?C8#U=NWRoTtLpE#DZO9f)Y(utc(qqUr zO|pgzX_7N!Sd(5uwrkR7$cQF+Lw0CVFl47D{jDTTqo4QiAd_*B9xBlj6HLk>z6U0W zQ+Sy9o@Y{;Ox80@)di;MZKmnRIEpKH2*0Oi{!9=4l_UR-NANFvMd!n~=IV-T9^(4i zH66#z-K+Dw?SVfcd6}`}5A-`}ezlM**u{{DwLu|9OUBw7YDuGY#@bqHokmN=+B#|} zqoreQJ+-vatXSJX%`#e7tZk&$WwcDJZK9SjT6e5%rq*pVJJz;PvyIjhYg?)H7%dxX z+o)xYmW#C^YB{6z#@aBoUZeHJ+IDJvM$5;VWI1oNLagneRxnzBtnH-MZ?u6cxV7bn z57-HSIrg|JESx|NC)raL*gJgogF63FJjRM^Fq;vxe+rLc5j8wcq zd+rS0r(-_Ev-mB}(kIW;CokeJcnN>QIs60XaTPD)Ke(W5yrK$tRc*jUHN-#Pcj7g* zn|~P&;7v7&x6~teN0s@$tmBee#JlP_yr<6LM=hVJ^UFSKZzad*O4Fgw(s|OS#8rh) zP~0<^yoAog(qM1u5>ma#mj)TrefWrqCErwbDY3)}9V`a$LNdhnc^x0HOn$;ES>ns; zr);o4V}t#W?e*s@o6BsUztBfAeQwwCku0{`hgleW+p{#{m&RROTN+S$B!3&5d+Yv9 hU;6|p{HpbQ%!cW{33g{W)}#0uBjE6p;zF~)e*tOs@TmX* literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/ExposedJsApi.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/ExposedJsApi.class new file mode 100644 index 0000000000000000000000000000000000000000..734c297b6b0b94ea2e1ad2c5201d8cd00dbe1f47 GIT binary patch literal 1362 zcmbVLT~8B16g^YguB_DsM6iNdzO)!sO12TIh-YOO7aNm`r;m*HK}sWdq; z^|;@#t5GQZ#>)TQ%wA1n$R+kvg&T^9fjJC@5@A=mv4$(H$s+DXGVmEp(&yESYt2A&#NV#x1y{7AOMzEqOzSo8fL;xU3@y2AZ>7|6Q)Ueu0d zWS2>=azojU96u7_A$J8CGO9$hO*vh$7nD^pv8~wrOwn=lEHYj0bu?{~5=zk(Wwj-g z;tfHhMvBhCwGLQ^VbI#~JsRLfmjsXr2c)4IbV65bN=+6iZZxQ zahB?iVH^+QnBgJqG*1$r5US9wv(1>$_$ksok!CDtfdnqbd~}YM)f4!OkBJFlmWn%S h6EF9hB%6|cZ!h=DT-Lt)&tB7*`Ae_I#4&{@KLL>8Ch!0N literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/FileHelper.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/FileHelper.class new file mode 100644 index 0000000000000000000000000000000000000000..af896930380f5804e29fe80dde81afb8dc06df50 GIT binary patch literal 4098 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 w%dnVh^c$?{*NjO@HsKOJ!#P4tFY}p7EUCj* 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 T_h{k6`#c}43PGHo^1kqYS$rk{ literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$1.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$1.class new file mode 100644 index 0000000000000000000000000000000000000000..d34928329e3d1a20f2d8385b882c20092c61fd21 GIT binary patch literal 255 zcma)%OA5k35Jao}MWbN$Zd|w#!69c51qBt+3$$Ys6T*ySk{r&32k=nhWbeXix|)LK zLA^iE7l0U}06~C|5T0#SXxXH>5GDsM(^@We=l0?pCvvK!l4Zs<6UJ+!bL&!*?4`Wh zTYw>9VT(lZgY{jMw#CiXtbS8wF#&|p))*;PIXfqg5H)O-vq{wPnu#t6^S_bN)B{_- YP@}dV_|!qy-wt}-2Yy5ULrseMU;7S36#xJL literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$BridgeMode.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$BridgeMode.class new file mode 100644 index 0000000000000000000000000000000000000000..02e11fc8f8e25d2ab4206176058a046d522b5ef6 GIT binary patch literal 1089 zcmb7CO>fgc5Pj=7c4}N=0u)5r5+Fbti<(G6OVu9{#1Crj7Ku(-XTweTpY>w$$>}`J`o=>k%?Uzdl5uI`jTP0v&7uiF@wG* zM}nc=4W@R-Me%4bDg(POY)$H8bK4vJCxT@;CUFXTxg=->0j z3AF#hkcM>`&FOoU^B^qwR62_8Y9!NO{ADoS53^)S^gAc2Tp!2sY!HPc;%zRXl!2Wv zRAZ5d)WjnOFnn6Znk7W^b`=BdoE}X(?=d`CYL?9WD6`lX`+;)3IcGuf#M`Gl=Qe6s zv0=beQNzSzhMk4C7Xo9!<+^R@w1~ kfPp6Yp;Q@I#|9y2*rZIuUDWArP^9AluId_Y(+#Kg8$!_hEC2ui literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$JsMessage.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$JsMessage.class new file mode 100644 index 0000000000000000000000000000000000000000..f9c28e6ecfb89fa0c0c4e0997c9533781605e229 GIT binary patch literal 3122 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 HC!W4vzUQEX literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$OnlineEventsBridgeMode$2.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$OnlineEventsBridgeMode$2.class new file mode 100644 index 0000000000000000000000000000000000000000..e847f210570dfec352a1cbcbbd5299ee9b3b824b GIT binary patch literal 1266 zcmb_cZEw<06n-w$b#zsb`8MYZXjKZj0!|Y%V{{DS7GS+Irp4G`mxrMU8FuS_ z(6{&}ZV!ZI`$5kiajVHAXC#jNgRmjOkoU#gp%@BdG2{*rKX*JQdcjc5Ee~h57?jFH zYqCx$G>0F%A~@n*m(-{0zRleh4;(q41r?b$0~q#}rZ>uzPdpfUWOGuA_TC=`wx~Ih zesl58Y#s9vXGm5(+x0`o>o-I+@OwJekkpaFhK@W6Ivz^%2wN&F9Ys*3$~qono64|k z6^t@NO3JWY?)9z1?y;~V+OK)&-O%%b9QsSr$wT9^AB03{hxn?D7Mj}dQ6M;SwzIHx!_#)|S4>Kr%?g)nMJ ru-8blePr0dA0*isNgUS+Hik{ypiv;cGGK@RU5F)_KoVp^d<6$tjvdEjG0-cGI%u+L5$;0SH8$j;Vmy7f4tQ+i_)89{cOfmUk#{)pr_=CN=&Kj{E&i z%eKwOO#)3;zB7-^LesPxg_qhg)volUf6hAUA6j0zD3Gr>Zlhp6HEV~mP;=b6Ly)TJ zTSs!&x$kXC&odixyCqwaXwgN>w*0#S^O+IWW%mTaE1m5oDvUz4_2jX1cLUy+D^AU9 z?wPKo#$9Dt(Gyr6-buQDfXO-1iGaXZM)8<+>~p(YIx?+hz-GdBeCy!Z)Y+Q0k>e_bb$v?};LZpISkCr4K`X&!w_*FzJuqwPdb{3-&8ucS2@UBl)p$c% z{xgA@Otxa$b=R@#yhfiEUe2hyx1U~M!fn}G_9JWe(3NIgU^>(9>dx+Aj;~9SFHr;` zRqvESs^r-xRdIHDmKKLebpSYy(SqlJugIGm?IFxDkj~}X2)TV<@Yr`s~F6te#ABM3O&b_ z9DDH`TKFe~$J!8QJcGUOa_^6j5?^(&r-JpTTxXGC4g?d!`=;wE5~Ki?lZe`Mf0!V-e>XC|7B?YB=IgpC!iI>I@rOa%j7OOJsl!l3?bBGb+VZkr!T%9OGCm7Ml1NVZ znthI9sv2*!p`+BcCq1FU!F0L3Qp3d#0fax}>^#O;)tVv5y5nnDcU8idv9JX1x9-MG z`CS=0*Hhc{Z@2$f^n{N|O!;u&8f($TE}@qB{Av0KhuP7iH}poGAbSlar<6Gx1^(+N z_!Uq-Z+2!Y2g^{vxAfRM>id9S4jy2Y1A0X6p5qp#Svs5r+JVouZ)}#IkY^3dVSZR6 zV9$J`kHF#xkOn};GV4R&Ik(9%&?yIxY4o6NVUY3O*1;05VcI!Z#tK)ku*#l=HO#VJ V<9r*NnBm9*Yvd=HfK6=M)*DK_1?K<& literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$PrivateApiBridgeMode.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/NativeToJsMessageQueue$PrivateApiBridgeMode.class new file mode 100644 index 0000000000000000000000000000000000000000..0745fb96dcb1b92e181024f8fd879829d48e98aa GIT binary patch literal 3053 zcmb7GZBr9h6n;*K*$@{DiLYoiv}hqAL|UY!AQ}-W8X^jUFRgZyTwo#W;${idcWrg1 z?et~(v46nN&J=Vy(@w_^cBVh7({neQWLxB-}2QjT+CWxz2{aO&$72HtpnbiASif)E* z3sdsziy*Whav|hVkQWGPb~c1C<`m3JH9d$01&a!bgwV*M*-Be%{^5@?LjG;A6r zTQlrwt+*l@*wNR7mXa_E8!lfIY95+K&?w8Pl3eY0FxEUZnD-RWSLU ztY+(FF=d`Fxqe()5i5f21O}y{AwqY@HqLcU6a2$wfxX+6(G8JZS;`4(O3M`;f6csB zoYpK|u3e#Dx<}YOVd-Vf7U^aEjHMSC566f)W*EX6E^4KcV6D?zccpzZgB(}04C`_Q zSlu)T4IR>Hnk5|Y;8}%!R2RhpA0zgEk7s{s-ZEEZ7`)fyW~Gt?f?Cazbeps6Ip##d zM-G|BTga!&oV5y4z6Cz#P4A>_>BgMAORR}}Em@3PMl%YQsTWdaiFx8sX+QzT1;UN( zq;4C~_6$hKd}~Z9-&zkLxvjIz(MfZ~%8OAZDdFH-KsXfamSv!#3rQ7mB;?nK0#n5@ zZWH!aqh_cVbvrdvsS85m(u8G}^@6ZeSSTs5Rji<_VijvDzQi3uv|eDfEOOG8TpO~s zR2;+mTyCEFWJ1@^Icek!RlTTVui`H5sc6Sh1@~2Sppz+A%a;=wp>H#8#%7(OjoD^w zRyPVUdtSuE+A>$QD8$keW2J5d4^;Hyp^6jeQ}GCoRXo90gmB%n3I|nuji-dRI?rQE z6>h|GPIbALbrXiR+!QvgC_?Yn4R|X%&TU_iVVW%Dcb*F*) zJFd&ZYv4Nx$Gq3L?caNiDdtkMlGHgs?X4AuXQ(w8=fF4XT8>{zSkbB z{cp!rwH~e(&Wf!UQyFuPFu2Kup8H%EJd#@N4s`PSTFvtbndej6%X8h&TAK}+Ia|}Y zi=OQ8HrR9QcTrdaV;()Z) zfmZ%*poIwHIgVUyA4 zh-Bmbb?lDpiR?|j!oHao?6b;|c3~$+w+MshN)%Z{If?}YX%Q+dAxZ}JlZkd(=2l!n z7u`mZ%IKw4^wS#7&>f7?UF7K=7U?lRoDX2qL)i2P_vwj)#yO5TioN&J@2zC{~-hd6zYA^Hhv`hhX{5f|uZC)POobOw!XG;M6{6i#ytapql`cO-u@l?cO- zZ*qkfILkZoUu__scnR8^Rk4bOi;ra7D6>>DEr3sPjxG2w#w#Dr<3pZXS^qHq%l?2R P!#pD#ux)2yASp#tt|n7!wDA0UP|lX@>>6;OmGhqKC1Q zCG9qM-PUbs)-0P{H%(G!tZSOuX$($jV$Y;;lXh*lw&~Jt-Ii`$A6p+=_iDRl-*fIo zl82h%eD=>h_niAXzvuV&JHI2n^7Bu=0APc-t_WRtNlKJCLxxa@=1-uoFT@?|-FMZSGjGX0znP53h(K94WR#}_4=KbLENA?dy( z>AqZyui#br_^O7#l$&0YntV-?eq9p$m0bI4`SuOD^KZQPTQC03i`V7soATq|d+`q% zzU9L$I3soZM<2e8?-b#?_@0lCf0EOGmek+(;s=t^554$N;i}sJ4gaFyUp4$#00MfK zWf_T%SR|P=k^)8D$(=?r85uVOmh~shBaxKRK51@Cn9*@#XFST~sy-`bT1Mv)!%8J{ zKUDO@BhfvH*cEI2@ffMcbJu*i6RoFj$M9hL4gr79;mDClQ!HYQHw~l`+|(*i(h;|k zsfd-@8;PYUeEIEtyE{6EJ9|6&ws#Ki8R+WWG2FSgy+=SCC?rB?QDA%5K>M~H67BEo z81A^Ey{ng00_8i~_Ye2C5B2o5Zyz4$I?%~IT>_rTNIGdm1>EcL86^`iMIB{6XQ*h$;jv-qiHmrh{kD9ZzN?NF$Uuq&+d|P zYBST;HuA1a7~_;;By4F0W5Q@`zUwL&X1z*&<&jY-HM=Iz{8o8sjwJ#&GOts?DNNvnwObQ3UpeM6=76ZSAT%GO&Y0O z=ez27pfa>CJ7KO06ch7zJK75DdTV+vDgfKkW-MwXTBYj>k|P4a zUr0g^#-w8UWPGySigsF~D)xc81NDpcFmA<;{sZQ{#6y8u%W{{K(p|)IBo$APQkaZ# zDxQkO`Xk3;tZ>Ty3M)O~n427o4;Yq=d_o4YY%CF<$SIM`#axxzlidW_vbwxld1!(P zbmf#8i%G8SvDktbIz1ANcC$tfj3&%UiVD;%Hch&!h!rzsOt3yv9q#FmrN>Qcw~f`Pq61RmEX-J_KFCfM_9-V(>k1n%D6B+0&XgJ_Sd~W`Sq3ApVDWT))B&aib@!9CzI?7{S)o|ZHJe?RdZZ~D6tb&`#a zU&64CF^uat1XIWF;z1pUag_OyPmI9Z^7t>mfZA;F)iHumf!3w(UDUHkt^Vz*SmbGi zZd*}m` zTS7Yi9seO8|Ec4@@SujD==dpqMvenUDrBkdXKh>eKxl#$Ih2ZrcraV(SWL%%DAt9J59y*rlxm_( z7v*wuh42g9v~)jZ+@Rwa?$vP@-Y%m}xs}4NY;^XigaMbgFJFZL#}`TXpsKIjz&WgmF*WOc-@*oQ0-IRg;?{Rx}Ye zqfL``o4lreoqX%FMvc1q*83aR*SAV--ml{nJ}6MTBc2M`J41Fc4o#VV!trr9c-Uv0C6d%V7H&ReH!E(;ap#4n>WWG0IQt1nQR@7oM6~Bl<=T zlLK3`C2z0YAaK{!6t;XPS{Clk>0~$V8&o^uiA+waQ-5u~LwL~vy3on6#bYP?4pGL$gZHoil@x6V|`<{$I?l*)n3zS z_o)7YpOnvY+CaZ@)fKDs&Y?)M*EmXOx-2zZ+1J^)r2)kWVK&5OMcD=>&Xyx{NU ztN_b6--rE~`4Fzbfh*=dS8~kpjwM?&c;B!^F&nN*@~!<-3Z4D(jLa$ ze8xEY41YtBzc7r1XW@tg4SEYk3+AP2EXt)R{59BAwVxx`Ipb&n(7$@ zXRzWts`pJJRecJYn6`aYy>Vxw6#pdNk=;_mEsdAq^{Q) zm5nc8=SnEI|hz;p|?5;k|^zgY?D+=)whO-%Q7*Nnap6ka7Dd?s+@? zBV^BI`$^GA2vvuNdM??j)`kmaa6HW%qeR6q z{)BliGvL0Q&{R9Z3uGtbh#ci^7kN}R%;3gbYR+R#@7fvE)f{vk%tpCXLFNGpcqh~B zU5aJc-j=balA?Z@Ox^U;{j{urltp-ez$@fC+ayQeVMkz<6xi0dl2I=Y&7gi?10xd7 zLffzSA1A+e)0Fqn(BH_BTa}Sp<;Vr9@GJOLa(6Q^e~lUxQsQy$wlVk>&WmX1 z>D$W71X$zz8Tm@+H8{vPVXqdp6*jxj|v1x!)vNY2lz2 zbkE{#$33Ke-BINvii7TQCVc(ApqsdE@dQ0oxW(HzAM{?Jdt7w&MVeHGS~cE)3u?TG z7u9IvVvH35cps@BA})T9)DL4hexEhs5!^tauc2LGoMaXK0IS9+g8G95^M~l{#|Yxb znZzGv7*EsvPjcrUk>WI-z(?>DK8k1YG0fpa07CAl6 zYWT)nz%4=H@!u?$lps})7X(xUJ>~aHyeR7LOO`8Iw4g@wTZ$UygGCpZ1TIvHO8Rmc zFG3u7jajbdHd-FQDt?pB5|;5>Fa<6(rte398~1 z(neMgKXH(ClsJEg*l|Yj362e|KCW2}Ah{N(_vXqeS;vrV)U*_LBhg*0Sww=eV`_8g9 z-u4XIXRvJnTy0$HXm+hUfuexx1YBp8B8{`y-r^3++L5D9SY`pfLjm7KCBDb_{eU_4 zL#)M*&`dvV#*gXWpVD(bQ|h+aie%L7!XGe(^3?BQZP-I&*3kDS>9a!esGLEI?Mx8BD2wLIS> zLIc=H9#xF895-T<8f}E$sLJ>oa8bcx;-^wD&ccON!i^h+hlSdU&7vqL5L+^qZBZJ_ zKs?F{XZLMSQ=ZhgTdKsItUduhHQtdEk8t%ltgb$ZddDcCS_s)puqDc8gY;NCwv+32 z>`-Hl?)*`rSd?LfsG!b%TufcC+PP*5$_?-J3Yd zIJwz#y3X*$7Grm1*DE%5SLSBPX1mADA7*OWhG#cFi^8RCevKu1*lz*G<=IG@(;3{DDd|OoC7W^OMn!|Dc literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/PluginEntry.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/PluginEntry.class new file mode 100644 index 0000000000000000000000000000000000000000..3f5f68af182c7a55b0cc107a17426ceb915add3d GIT binary patch literal 1899 zcmcIk+fEZv6kVtE0z(l*1yP~JYZ=gbLAgqzc(*|XtqE^Knba}E44FiMcH2O;p&DAH)Xgb z!?X;yGq{t%j6$Yn2Rly1Rv0Y3w|1wUYs1xM z_!Y}7TY)3{=3z2?=a7BA6LzHfp%(_bq*my}sLkGWp)mV*p+_uPkkp~lA(Fe>zla(S z?Crp=SfNe#OaD}$qvuj|WVP;v&X!$vY7VWr=Xri;g^ushnW2{Na6o~6tp6p4KXz3o z8@&Gn{#y(Bs&@FMrJV;06GwR|Ty8t;h{r!;&94U)n?DEpZlI-)u1UjWF^jnj=CfG9 zViv==B*Wb-vgpg=m<-1;n8gX4%%UFy3S%8iY(Zs>gGPL@@!qb43f)xH{KrrH;;kP7 zeaH{ke~{CR%P?id+9KzZhce=)qpL7c#yH=aUOrDLC}GT%64H7mTRoFM=Y&Y$?J2z; z(iy`z&65$HtRjsr&I9J;)E?9x63HpGkFL);`V2>d2*4aYn8#VJ@=-j_VU#;&>iSBr zq;i7D!x(Ggmx-U`ok9Fj)d~4Nda$gK%_uTPHezH$YZD%Zd=)Z~8ac*`h7YWn;+!-0 zku)b8NSRX&q|MO=GUiCKfo@YZ&?Az%Ad<$A;rNK@k6HW)!JpEkX9RoByOJg|9YMxq zaxs})OeWVP!_wO1B+UWi#0)tZVuf+8(KP=&E^wXZ{YB0RX*!M~;UniX=X^&ADUl#T z+BB@N!V7A6Nlvd=ag}Imto>SRSc))X4f$9@KGu+rHRPquiANS%O{ztWoJi|LO>~(G ouAtE5UgS;`r_3+t{=`K>n=CScx0*;~NvcUC0-4~wsiP-<0+V8x)Bpeg literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/PluginManager.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/PluginManager.class new file mode 100644 index 0000000000000000000000000000000000000000..f6d3a47d041f4d366c029a0143a876c3a111d41c GIT binary patch literal 9922 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 CL2Lp5 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/PluginResult.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/PluginResult.class new file mode 100644 index 0000000000000000000000000000000000000000..44dc171780335f5b776ae5650623e635d4b293bd GIT binary patch literal 4933 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 literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/Whitelist$URLPattern.class b/platforms/android/CordovaLib/ant-build/classes/org/apache/cordova/Whitelist$URLPattern.class new file mode 100644 index 0000000000000000000000000000000000000000..0ae6882279731ed919fbbb719aa27bb318aebaab GIT binary patch literal 2995 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 E3;NR46951J literal 0 HcmV?d00001 diff --git a/platforms/android/CordovaLib/ant-build/proguard.txt b/platforms/android/CordovaLib/ant-build/proguard.txt new file mode 100644 index 0000000..e69de29 diff --git a/platforms/android/CordovaLib/build.gradle b/platforms/android/CordovaLib/build.gradle new file mode 100644 index 0000000..47341b3 --- /dev/null +++ b/platforms/android/CordovaLib/build.gradle @@ -0,0 +1,54 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + + + +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:0.10.+' + } +} + +apply plugin: 'android-library' + +android { + compileSdkVersion 19 + buildToolsVersion "19.0.0" + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + resources.srcDirs = ['src'] + aidl.srcDirs = ['src'] + renderscript.srcDirs = ['src'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + } + } +} diff --git a/platforms/android/CordovaLib/project.properties b/platforms/android/CordovaLib/project.properties new file mode 100644 index 0000000..9fe04f3 --- /dev/null +++ b/platforms/android/CordovaLib/project.properties @@ -0,0 +1,16 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Indicates whether an apk should be generated for each density. +split.density=false +# Project target. +target=android-19 +apk-configurations= +renderscript.opt.level=O0 +android.library=true diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/Address.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/Address.java new file mode 100755 index 0000000..b34bd91 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/Address.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.Util; +import java.net.Proxy; +import java.net.UnknownHostException; +import java.util.List; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSocketFactory; + +import static com.squareup.okhttp.internal.Util.equal; + +/** + * A specification for a connection to an origin server. For simple connections, + * this is the server's hostname and port. If an explicit proxy is requested (or + * {@link Proxy#NO_PROXY no proxy} is explicitly requested), this also includes + * that proxy information. For secure connections the address also includes the + * SSL socket factory and hostname verifier. + * + *

HTTP requests that share the same {@code Address} may also share the same + * {@link Connection}. + */ +public final class Address { + final Proxy proxy; + final String uriHost; + final int uriPort; + final SSLSocketFactory sslSocketFactory; + final HostnameVerifier hostnameVerifier; + final OkAuthenticator authenticator; + final List transports; + + public Address(String uriHost, int uriPort, SSLSocketFactory sslSocketFactory, + HostnameVerifier hostnameVerifier, OkAuthenticator authenticator, Proxy proxy, + List transports) throws UnknownHostException { + if (uriHost == null) throw new NullPointerException("uriHost == null"); + if (uriPort <= 0) throw new IllegalArgumentException("uriPort <= 0: " + uriPort); + if (authenticator == null) throw new IllegalArgumentException("authenticator == null"); + if (transports == null) throw new IllegalArgumentException("transports == null"); + this.proxy = proxy; + this.uriHost = uriHost; + this.uriPort = uriPort; + this.sslSocketFactory = sslSocketFactory; + this.hostnameVerifier = hostnameVerifier; + this.authenticator = authenticator; + this.transports = Util.immutableList(transports); + } + + /** Returns the hostname of the origin server. */ + public String getUriHost() { + return uriHost; + } + + /** + * Returns the port of the origin server; typically 80 or 443. Unlike + * may {@code getPort()} accessors, this method never returns -1. + */ + public int getUriPort() { + return uriPort; + } + + /** + * Returns the SSL socket factory, or null if this is not an HTTPS + * address. + */ + public SSLSocketFactory getSslSocketFactory() { + return sslSocketFactory; + } + + /** + * Returns the hostname verifier, or null if this is not an HTTPS + * address. + */ + public HostnameVerifier getHostnameVerifier() { + return hostnameVerifier; + } + + + /** + * Returns the client's authenticator. This method never returns null. + */ + public OkAuthenticator getAuthenticator() { + return authenticator; + } + + /** + * Returns the client's transports. This method always returns a non-null list + * that contains "http/1.1", possibly among other transports. + */ + public List getTransports() { + return transports; + } + + /** + * Returns this address's explicitly-specified HTTP proxy, or null to + * delegate to the HTTP client's proxy selector. + */ + public Proxy getProxy() { + return proxy; + } + + @Override public boolean equals(Object other) { + if (other instanceof Address) { + Address that = (Address) other; + return equal(this.proxy, that.proxy) + && this.uriHost.equals(that.uriHost) + && this.uriPort == that.uriPort + && equal(this.sslSocketFactory, that.sslSocketFactory) + && equal(this.hostnameVerifier, that.hostnameVerifier) + && equal(this.authenticator, that.authenticator) + && equal(this.transports, that.transports); + } + return false; + } + + @Override public int hashCode() { + int result = 17; + result = 31 * result + uriHost.hashCode(); + result = 31 * result + uriPort; + result = 31 * result + (sslSocketFactory != null ? sslSocketFactory.hashCode() : 0); + result = 31 * result + (hostnameVerifier != null ? hostnameVerifier.hashCode() : 0); + result = 31 * result + (authenticator != null ? authenticator.hashCode() : 0); + result = 31 * result + (proxy != null ? proxy.hashCode() : 0); + result = 31 * result + transports.hashCode(); + return result; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/Connection.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/Connection.java new file mode 100755 index 0000000..6bb9cb3 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/Connection.java @@ -0,0 +1,335 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.Platform; +import com.squareup.okhttp.internal.http.HttpAuthenticator; +import com.squareup.okhttp.internal.http.HttpEngine; +import com.squareup.okhttp.internal.http.HttpTransport; +import com.squareup.okhttp.internal.http.RawHeaders; +import com.squareup.okhttp.internal.http.SpdyTransport; +import com.squareup.okhttp.internal.spdy.SpdyConnection; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Proxy; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.util.Arrays; +import javax.net.ssl.SSLSocket; + +import static java.net.HttpURLConnection.HTTP_OK; +import static java.net.HttpURLConnection.HTTP_PROXY_AUTH; + +/** + * Holds the sockets and streams of an HTTP, HTTPS, or HTTPS+SPDY connection, + * which may be used for multiple HTTP request/response exchanges. Connections + * may be direct to the origin server or via a proxy. + * + *

Typically instances of this class are created, connected and exercised + * automatically by the HTTP client. Applications may use this class to monitor + * HTTP connections as members of a {@link ConnectionPool connection pool}. + * + *

Do not confuse this class with the misnamed {@code HttpURLConnection}, + * which isn't so much a connection as a single request/response exchange. + * + *

Modern TLS

+ * There are tradeoffs when selecting which options to include when negotiating + * a secure connection to a remote host. Newer TLS options are quite useful: + *
    + *
  • Server Name Indication (SNI) enables one IP address to negotiate secure + * connections for multiple domain names. + *
  • Next Protocol Negotiation (NPN) enables the HTTPS port (443) to be used + * for both HTTP and SPDY transports. + *
+ * Unfortunately, older HTTPS servers refuse to connect when such options are + * presented. Rather than avoiding these options entirely, this class allows a + * connection to be attempted with modern options and then retried without them + * should the attempt fail. + */ +public final class Connection implements Closeable { + private static final byte[] NPN_PROTOCOLS = new byte[] { + 6, 's', 'p', 'd', 'y', '/', '3', + 8, 'h', 't', 't', 'p', '/', '1', '.', '1' + }; + private static final byte[] SPDY3 = new byte[] { + 's', 'p', 'd', 'y', '/', '3' + }; + private static final byte[] HTTP_11 = new byte[] { + 'h', 't', 't', 'p', '/', '1', '.', '1' + }; + + private final Route route; + + private Socket socket; + private InputStream in; + private OutputStream out; + private boolean connected = false; + private SpdyConnection spdyConnection; + private int httpMinorVersion = 1; // Assume HTTP/1.1 + private long idleStartTimeNs; + + public Connection(Route route) { + this.route = route; + } + + public void connect(int connectTimeout, int readTimeout, TunnelRequest tunnelRequest) + throws IOException { + if (connected) throw new IllegalStateException("already connected"); + + socket = (route.proxy.type() != Proxy.Type.HTTP) ? new Socket(route.proxy) : new Socket(); + Platform.get().connectSocket(socket, route.inetSocketAddress, connectTimeout); + socket.setSoTimeout(readTimeout); + in = socket.getInputStream(); + out = socket.getOutputStream(); + + if (route.address.sslSocketFactory != null) { + upgradeToTls(tunnelRequest); + } else { + streamWrapper(); + } + connected = true; + } + + /** + * Create an {@code SSLSocket} and perform the TLS handshake and certificate + * validation. + */ + private void upgradeToTls(TunnelRequest tunnelRequest) throws IOException { + Platform platform = Platform.get(); + + // Make an SSL Tunnel on the first message pair of each SSL + proxy connection. + if (requiresTunnel()) { + makeTunnel(tunnelRequest); + } + + // Create the wrapper over connected socket. + socket = route.address.sslSocketFactory + .createSocket(socket, route.address.uriHost, route.address.uriPort, true /* autoClose */); + SSLSocket sslSocket = (SSLSocket) socket; + if (route.modernTls) { + platform.enableTlsExtensions(sslSocket, route.address.uriHost); + } else { + platform.supportTlsIntolerantServer(sslSocket); + } + + boolean useNpn = route.modernTls && route.address.transports.contains("spdy/3"); + if (useNpn) { + platform.setNpnProtocols(sslSocket, NPN_PROTOCOLS); + } + + // Force handshake. This can throw! + sslSocket.startHandshake(); + + // Verify that the socket's certificates are acceptable for the target host. + if (!route.address.hostnameVerifier.verify(route.address.uriHost, sslSocket.getSession())) { + throw new IOException("Hostname '" + route.address.uriHost + "' was not verified"); + } + + out = sslSocket.getOutputStream(); + in = sslSocket.getInputStream(); + streamWrapper(); + + byte[] selectedProtocol; + if (useNpn && (selectedProtocol = platform.getNpnSelectedProtocol(sslSocket)) != null) { + if (Arrays.equals(selectedProtocol, SPDY3)) { + sslSocket.setSoTimeout(0); // SPDY timeouts are set per-stream. + spdyConnection = new SpdyConnection.Builder(route.address.getUriHost(), true, in, out) + .build(); + spdyConnection.sendConnectionHeader(); + } else if (!Arrays.equals(selectedProtocol, HTTP_11)) { + throw new IOException( + "Unexpected NPN transport " + new String(selectedProtocol, "ISO-8859-1")); + } + } + } + + /** Returns true if {@link #connect} has been attempted on this connection. */ + public boolean isConnected() { + return connected; + } + + @Override public void close() throws IOException { + socket.close(); + } + + /** Returns the route used by this connection. */ + public Route getRoute() { + return route; + } + + /** + * Returns the socket that this connection uses, or null if the connection + * is not currently connected. + */ + public Socket getSocket() { + return socket; + } + + /** Returns true if this connection is alive. */ + public boolean isAlive() { + return !socket.isClosed() && !socket.isInputShutdown() && !socket.isOutputShutdown(); + } + + /** + * Returns true if we are confident that we can read data from this + * connection. This is more expensive and more accurate than {@link + * #isAlive()}; callers should check {@link #isAlive()} first. + */ + public boolean isReadable() { + if (!(in instanceof BufferedInputStream)) { + return true; // Optimistic. + } + if (isSpdy()) { + return true; // Optimistic. We can't test SPDY because its streams are in use. + } + BufferedInputStream bufferedInputStream = (BufferedInputStream) in; + try { + int readTimeout = socket.getSoTimeout(); + try { + socket.setSoTimeout(1); + bufferedInputStream.mark(1); + if (bufferedInputStream.read() == -1) { + return false; // Stream is exhausted; socket is closed. + } + bufferedInputStream.reset(); + return true; + } finally { + socket.setSoTimeout(readTimeout); + } + } catch (SocketTimeoutException ignored) { + return true; // Read timed out; socket is good. + } catch (IOException e) { + return false; // Couldn't read; socket is closed. + } + } + + public void resetIdleStartTime() { + if (spdyConnection != null) { + throw new IllegalStateException("spdyConnection != null"); + } + this.idleStartTimeNs = System.nanoTime(); + } + + /** Returns true if this connection is idle. */ + public boolean isIdle() { + return spdyConnection == null || spdyConnection.isIdle(); + } + + /** + * Returns true if this connection has been idle for longer than + * {@code keepAliveDurationNs}. + */ + public boolean isExpired(long keepAliveDurationNs) { + return getIdleStartTimeNs() < System.nanoTime() - keepAliveDurationNs; + } + + /** + * Returns the time in ns when this connection became idle. Undefined if + * this connection is not idle. + */ + public long getIdleStartTimeNs() { + return spdyConnection == null ? idleStartTimeNs : spdyConnection.getIdleStartTimeNs(); + } + + /** Returns the transport appropriate for this connection. */ + public Object newTransport(HttpEngine httpEngine) throws IOException { + return (spdyConnection != null) + ? new SpdyTransport(httpEngine, spdyConnection) + : new HttpTransport(httpEngine, out, in); + } + + /** + * Returns true if this is a SPDY connection. Such connections can be used + * in multiple HTTP requests simultaneously. + */ + public boolean isSpdy() { + return spdyConnection != null; + } + + public SpdyConnection getSpdyConnection() { + return spdyConnection; + } + + /** + * Returns the minor HTTP version that should be used for future requests on + * this connection. Either 0 for HTTP/1.0, or 1 for HTTP/1.1. The default + * value is 1 for new connections. + */ + public int getHttpMinorVersion() { + return httpMinorVersion; + } + + public void setHttpMinorVersion(int httpMinorVersion) { + this.httpMinorVersion = httpMinorVersion; + } + + /** + * Returns true if the HTTP connection needs to tunnel one protocol over + * another, such as when using HTTPS through an HTTP proxy. When doing so, + * we must avoid buffering bytes intended for the higher-level protocol. + */ + public boolean requiresTunnel() { + return route.address.sslSocketFactory != null && route.proxy.type() == Proxy.Type.HTTP; + } + + public void updateReadTimeout(int newTimeout) throws IOException { + if (!connected) throw new IllegalStateException("updateReadTimeout - not connected"); + socket.setSoTimeout(newTimeout); + } + + /** + * To make an HTTPS connection over an HTTP proxy, send an unencrypted + * CONNECT request to create the proxy connection. This may need to be + * retried if the proxy requires authorization. + */ + private void makeTunnel(TunnelRequest tunnelRequest) throws IOException { + RawHeaders requestHeaders = tunnelRequest.getRequestHeaders(); + while (true) { + out.write(requestHeaders.toBytes()); + RawHeaders responseHeaders = RawHeaders.fromBytes(in); + + switch (responseHeaders.getResponseCode()) { + case HTTP_OK: + return; + case HTTP_PROXY_AUTH: + requestHeaders = new RawHeaders(requestHeaders); + URL url = new URL("https", tunnelRequest.host, tunnelRequest.port, "/"); + boolean credentialsFound = HttpAuthenticator.processAuthHeader( + route.address.authenticator, HTTP_PROXY_AUTH, responseHeaders, requestHeaders, + route.proxy, url); + if (credentialsFound) { + continue; + } else { + throw new IOException("Failed to authenticate with proxy"); + } + default: + throw new IOException( + "Unexpected response code for CONNECT: " + responseHeaders.getResponseCode()); + } + } + } + + private void streamWrapper() throws IOException { + in = new BufferedInputStream(in, 4096); + out = new BufferedOutputStream(out, 256); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/ConnectionPool.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/ConnectionPool.java new file mode 100755 index 0000000..42b70b9 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/ConnectionPool.java @@ -0,0 +1,274 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.Platform; +import com.squareup.okhttp.internal.Util; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Manages reuse of HTTP and SPDY connections for reduced network latency. HTTP + * requests that share the same {@link com.squareup.okhttp.Address} may share a + * {@link com.squareup.okhttp.Connection}. This class implements the policy of + * which connections to keep open for future use. + * + *

The {@link #getDefault() system-wide default} uses system properties for + * tuning parameters: + *

    + *
  • {@code http.keepAlive} true if HTTP and SPDY connections should be + * pooled at all. Default is true. + *
  • {@code http.maxConnections} maximum number of idle connections to + * each to keep in the pool. Default is 5. + *
  • {@code http.keepAliveDuration} Time in milliseconds to keep the + * connection alive in the pool before closing it. Default is 5 minutes. + * This property isn't used by {@code HttpURLConnection}. + *
+ * + *

The default instance doesn't adjust its configuration as system + * properties are changed. This assumes that the applications that set these + * parameters do so before making HTTP connections, and that this class is + * initialized lazily. + */ +public class ConnectionPool { + private static final int MAX_CONNECTIONS_TO_CLEANUP = 2; + private static final long DEFAULT_KEEP_ALIVE_DURATION_MS = 5 * 60 * 1000; // 5 min + + private static final ConnectionPool systemDefault; + + static { + String keepAlive = System.getProperty("http.keepAlive"); + String keepAliveDuration = System.getProperty("http.keepAliveDuration"); + String maxIdleConnections = System.getProperty("http.maxConnections"); + long keepAliveDurationMs = keepAliveDuration != null ? Long.parseLong(keepAliveDuration) + : DEFAULT_KEEP_ALIVE_DURATION_MS; + if (keepAlive != null && !Boolean.parseBoolean(keepAlive)) { + systemDefault = new ConnectionPool(0, keepAliveDurationMs); + } else if (maxIdleConnections != null) { + systemDefault = new ConnectionPool(Integer.parseInt(maxIdleConnections), keepAliveDurationMs); + } else { + systemDefault = new ConnectionPool(5, keepAliveDurationMs); + } + } + + /** The maximum number of idle connections for each address. */ + private final int maxIdleConnections; + private final long keepAliveDurationNs; + + private final LinkedList connections = new LinkedList(); + + /** We use a single background thread to cleanup expired connections. */ + private final ExecutorService executorService = new ThreadPoolExecutor(0, 1, + 60L, TimeUnit.SECONDS, new LinkedBlockingQueue(), + Util.daemonThreadFactory("OkHttp ConnectionPool")); + private final Callable connectionsCleanupCallable = new Callable() { + @Override public Void call() throws Exception { + List expiredConnections = new ArrayList(MAX_CONNECTIONS_TO_CLEANUP); + int idleConnectionCount = 0; + synchronized (ConnectionPool.this) { + for (ListIterator i = connections.listIterator(connections.size()); + i.hasPrevious(); ) { + Connection connection = i.previous(); + if (!connection.isAlive() || connection.isExpired(keepAliveDurationNs)) { + i.remove(); + expiredConnections.add(connection); + if (expiredConnections.size() == MAX_CONNECTIONS_TO_CLEANUP) break; + } else if (connection.isIdle()) { + idleConnectionCount++; + } + } + + for (ListIterator i = connections.listIterator(connections.size()); + i.hasPrevious() && idleConnectionCount > maxIdleConnections; ) { + Connection connection = i.previous(); + if (connection.isIdle()) { + expiredConnections.add(connection); + i.remove(); + --idleConnectionCount; + } + } + } + for (Connection expiredConnection : expiredConnections) { + Util.closeQuietly(expiredConnection); + } + return null; + } + }; + + public ConnectionPool(int maxIdleConnections, long keepAliveDurationMs) { + this.maxIdleConnections = maxIdleConnections; + this.keepAliveDurationNs = keepAliveDurationMs * 1000 * 1000; + } + + /** + * Returns a snapshot of the connections in this pool, ordered from newest to + * oldest. Waits for the cleanup callable to run if it is currently scheduled. + */ + List getConnections() { + waitForCleanupCallableToRun(); + synchronized (this) { + return new ArrayList(connections); + } + } + + /** + * Blocks until the executor service has processed all currently enqueued + * jobs. + */ + private void waitForCleanupCallableToRun() { + try { + executorService.submit(new Runnable() { + @Override public void run() { + } + }).get(); + } catch (Exception e) { + throw new AssertionError(); + } + } + + public static ConnectionPool getDefault() { + return systemDefault; + } + + /** Returns total number of connections in the pool. */ + public synchronized int getConnectionCount() { + return connections.size(); + } + + /** Returns total number of spdy connections in the pool. */ + public synchronized int getSpdyConnectionCount() { + int total = 0; + for (Connection connection : connections) { + if (connection.isSpdy()) total++; + } + return total; + } + + /** Returns total number of http connections in the pool. */ + public synchronized int getHttpConnectionCount() { + int total = 0; + for (Connection connection : connections) { + if (!connection.isSpdy()) total++; + } + return total; + } + + /** Returns a recycled connection to {@code address}, or null if no such connection exists. */ + public synchronized Connection get(Address address) { + Connection foundConnection = null; + for (ListIterator i = connections.listIterator(connections.size()); + i.hasPrevious(); ) { + Connection connection = i.previous(); + if (!connection.getRoute().getAddress().equals(address) + || !connection.isAlive() + || System.nanoTime() - connection.getIdleStartTimeNs() >= keepAliveDurationNs) { + continue; + } + i.remove(); + if (!connection.isSpdy()) { + try { + Platform.get().tagSocket(connection.getSocket()); + } catch (SocketException e) { + Util.closeQuietly(connection); + // When unable to tag, skip recycling and close + Platform.get().logW("Unable to tagSocket(): " + e); + continue; + } + } + foundConnection = connection; + break; + } + + if (foundConnection != null && foundConnection.isSpdy()) { + connections.addFirst(foundConnection); // Add it back after iteration. + } + + executorService.submit(connectionsCleanupCallable); + return foundConnection; + } + + /** + * Gives {@code connection} to the pool. The pool may store the connection, + * or close it, as its policy describes. + * + *

It is an error to use {@code connection} after calling this method. + */ + public void recycle(Connection connection) { + if (connection.isSpdy()) { + return; + } + + if (!connection.isAlive()) { + Util.closeQuietly(connection); + return; + } + + try { + Platform.get().untagSocket(connection.getSocket()); + } catch (SocketException e) { + // When unable to remove tagging, skip recycling and close. + Platform.get().logW("Unable to untagSocket(): " + e); + Util.closeQuietly(connection); + return; + } + + synchronized (this) { + connections.addFirst(connection); + connection.resetIdleStartTime(); + } + + executorService.submit(connectionsCleanupCallable); + } + + /** + * Shares the SPDY connection with the pool. Callers to this method may + * continue to use {@code connection}. + */ + public void maybeShare(Connection connection) { + executorService.submit(connectionsCleanupCallable); + if (!connection.isSpdy()) { + // Only SPDY connections are sharable. + return; + } + if (connection.isAlive()) { + synchronized (this) { + connections.addFirst(connection); + } + } + } + + /** Close and remove all connections in the pool. */ + public void evictAll() { + List connections; + synchronized (this) { + connections = new ArrayList(this.connections); + this.connections.clear(); + } + + for (Connection connection : connections) { + Util.closeQuietly(connection); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/Dispatcher.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/Dispatcher.java new file mode 100755 index 0000000..1982a8a --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/Dispatcher.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.http.ResponseHeaders; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +final class Dispatcher { + // TODO: thread pool size should be configurable; possibly configurable per host. + private final ThreadPoolExecutor executorService = new ThreadPoolExecutor( + 8, 8, 60, TimeUnit.SECONDS, new LinkedBlockingQueue()); + private final Map> enqueuedJobs = new LinkedHashMap>(); + + public synchronized void enqueue( + OkHttpClient client, Request request, Response.Receiver responseReceiver) { + Job job = new Job(this, client, request, responseReceiver); + List jobsForTag = enqueuedJobs.get(request.tag()); + if (jobsForTag == null) { + jobsForTag = new ArrayList(2); + enqueuedJobs.put(request.tag(), jobsForTag); + } + jobsForTag.add(job); + executorService.execute(job); + } + + public synchronized void cancel(Object tag) { + List jobs = enqueuedJobs.remove(tag); + if (jobs == null) return; + for (Job job : jobs) { + executorService.remove(job); + } + } + + synchronized void finished(Job job) { + List jobs = enqueuedJobs.get(job.tag()); + if (jobs != null) jobs.remove(job); + } + + static class RealResponseBody extends Response.Body { + private final ResponseHeaders responseHeaders; + private final InputStream in; + + RealResponseBody(ResponseHeaders responseHeaders, InputStream in) { + this.responseHeaders = responseHeaders; + this.in = in; + } + + @Override public boolean ready() throws IOException { + return true; + } + + @Override public MediaType contentType() { + String contentType = responseHeaders.getContentType(); + return contentType != null ? MediaType.parse(contentType) : null; + } + + @Override public long contentLength() { + return responseHeaders.getContentLength(); + } + + @Override public InputStream byteStream() throws IOException { + return in; + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/Failure.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/Failure.java new file mode 100755 index 0000000..a354700 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/Failure.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +/** + * A failure attempting to retrieve an HTTP response. + * + *

Warning: Experimental OkHttp 2.0 API

+ * This class is in beta. APIs are subject to change! + */ +/* OkHttp 2.0: public */ class Failure { + private final Request request; + private final Throwable exception; + + private Failure(Builder builder) { + this.request = builder.request; + this.exception = builder.exception; + } + + public Request request() { + return request; + } + + public Throwable exception() { + return exception; + } + + public static class Builder { + private Request request; + private Throwable exception; + + public Builder request(Request request) { + this.request = request; + return this; + } + + public Builder exception(Throwable exception) { + this.exception = exception; + return this; + } + + public Failure build() { + return new Failure(this); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/HttpResponseCache.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/HttpResponseCache.java new file mode 100755 index 0000000..8210318 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/HttpResponseCache.java @@ -0,0 +1,722 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.Base64; +import com.squareup.okhttp.internal.DiskLruCache; +import com.squareup.okhttp.internal.StrictLineReader; +import com.squareup.okhttp.internal.Util; +import com.squareup.okhttp.internal.http.HttpEngine; +import com.squareup.okhttp.internal.http.HttpURLConnectionImpl; +import com.squareup.okhttp.internal.http.HttpsEngine; +import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl; +import com.squareup.okhttp.internal.http.RawHeaders; +import com.squareup.okhttp.internal.http.ResponseHeaders; +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FilterInputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.net.CacheRequest; +import java.net.CacheResponse; +import java.net.HttpURLConnection; +import java.net.ResponseCache; +import java.net.SecureCacheResponse; +import java.net.URI; +import java.net.URLConnection; +import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSocket; + +import static com.squareup.okhttp.internal.Util.US_ASCII; +import static com.squareup.okhttp.internal.Util.UTF_8; + +/** + * Caches HTTP and HTTPS responses to the filesystem so they may be reused, + * saving time and bandwidth. + * + *

Cache Optimization

+ * To measure cache effectiveness, this class tracks three statistics: + *
    + *
  • {@link #getRequestCount() Request Count:} the number + * of HTTP requests issued since this cache was created. + *
  • {@link #getNetworkCount() Network Count:} the + * number of those requests that required network use. + *
  • {@link #getHitCount() Hit Count:} the number of + * those requests whose responses were served by the cache. + *
+ * Sometimes a request will result in a conditional cache hit. If the cache + * contains a stale copy of the response, the client will issue a conditional + * {@code GET}. The server will then send either the updated response if it has + * changed, or a short 'not modified' response if the client's copy is still + * valid. Such responses increment both the network count and hit count. + * + *

The best way to improve the cache hit rate is by configuring the web + * server to return cacheable responses. Although this client honors all HTTP/1.1 (RFC 2068) cache + * headers, it doesn't cache partial responses. + * + *

Force a Network Response

+ * In some situations, such as after a user clicks a 'refresh' button, it may be + * necessary to skip the cache, and fetch data directly from the server. To force + * a full refresh, add the {@code no-cache} directive:
   {@code
+ *         connection.addRequestProperty("Cache-Control", "no-cache");
+ * }
+ * If it is only necessary to force a cached response to be validated by the + * server, use the more efficient {@code max-age=0} instead:
   {@code
+ *         connection.addRequestProperty("Cache-Control", "max-age=0");
+ * }
+ * + *

Force a Cache Response

+ * Sometimes you'll want to show resources if they are available immediately, + * but not otherwise. This can be used so your application can show + * something while waiting for the latest data to be downloaded. To + * restrict a request to locally-cached resources, add the {@code + * only-if-cached} directive:
   {@code
+ *     try {
+ *         connection.addRequestProperty("Cache-Control", "only-if-cached");
+ *         InputStream cached = connection.getInputStream();
+ *         // the resource was cached! show it
+ *     } catch (FileNotFoundException e) {
+ *         // the resource was not cached
+ *     }
+ * }
+ * This technique works even better in situations where a stale response is + * better than no response. To permit stale cached responses, use the {@code + * max-stale} directive with the maximum staleness in seconds:
   {@code
+ *         int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
+ *         connection.addRequestProperty("Cache-Control", "max-stale=" + maxStale);
+ * }
+ */ +public final class HttpResponseCache extends ResponseCache { + // TODO: add APIs to iterate the cache? + private static final int VERSION = 201105; + private static final int ENTRY_METADATA = 0; + private static final int ENTRY_BODY = 1; + private static final int ENTRY_COUNT = 2; + + private final DiskLruCache cache; + + /* read and write statistics, all guarded by 'this' */ + private int writeSuccessCount; + private int writeAbortCount; + private int networkCount; + private int hitCount; + private int requestCount; + + /** + * Although this class only exposes the limited ResponseCache API, it + * implements the full OkResponseCache interface. This field is used as a + * package private handle to the complete implementation. It delegates to + * public and private members of this type. + */ + final OkResponseCache okResponseCache = new OkResponseCache() { + @Override public CacheResponse get(URI uri, String requestMethod, + Map> requestHeaders) throws IOException { + return HttpResponseCache.this.get(uri, requestMethod, requestHeaders); + } + + @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { + return HttpResponseCache.this.put(uri, connection); + } + + @Override public void maybeRemove(String requestMethod, URI uri) throws IOException { + HttpResponseCache.this.maybeRemove(requestMethod, uri); + } + + @Override public void update( + CacheResponse conditionalCacheHit, HttpURLConnection connection) throws IOException { + HttpResponseCache.this.update(conditionalCacheHit, connection); + } + + @Override public void trackConditionalCacheHit() { + HttpResponseCache.this.trackConditionalCacheHit(); + } + + @Override public void trackResponse(ResponseSource source) { + HttpResponseCache.this.trackResponse(source); + } + }; + + public HttpResponseCache(File directory, long maxSize) throws IOException { + cache = DiskLruCache.open(directory, VERSION, ENTRY_COUNT, maxSize); + } + + private String uriToKey(URI uri) { + return Util.hash(uri.toString()); + } + + @Override public CacheResponse get(URI uri, String requestMethod, + Map> requestHeaders) { + String key = uriToKey(uri); + DiskLruCache.Snapshot snapshot; + Entry entry; + try { + snapshot = cache.get(key); + if (snapshot == null) { + return null; + } + entry = new Entry(snapshot.getInputStream(ENTRY_METADATA)); + } catch (IOException e) { + // Give up because the cache cannot be read. + return null; + } + + if (!entry.matches(uri, requestMethod, requestHeaders)) { + snapshot.close(); + return null; + } + + return entry.isHttps() ? new EntrySecureCacheResponse(entry, snapshot) + : new EntryCacheResponse(entry, snapshot); + } + + @Override public CacheRequest put(URI uri, URLConnection urlConnection) throws IOException { + if (!(urlConnection instanceof HttpURLConnection)) { + return null; + } + + HttpURLConnection httpConnection = (HttpURLConnection) urlConnection; + String requestMethod = httpConnection.getRequestMethod(); + + if (maybeRemove(requestMethod, uri)) { + return null; + } + if (!requestMethod.equals("GET")) { + // Don't cache non-GET responses. We're technically allowed to cache + // HEAD requests and some POST requests, but the complexity of doing + // so is high and the benefit is low. + return null; + } + + HttpEngine httpEngine = getHttpEngine(httpConnection); + if (httpEngine == null) { + // Don't cache unless the HTTP implementation is ours. + return null; + } + + ResponseHeaders response = httpEngine.getResponseHeaders(); + if (response.hasVaryAll()) { + return null; + } + + RawHeaders varyHeaders = + httpEngine.getRequestHeaders().getHeaders().getAll(response.getVaryFields()); + Entry entry = new Entry(uri, varyHeaders, httpConnection); + DiskLruCache.Editor editor = null; + try { + editor = cache.edit(uriToKey(uri)); + if (editor == null) { + return null; + } + entry.writeTo(editor); + return new CacheRequestImpl(editor); + } catch (IOException e) { + abortQuietly(editor); + return null; + } + } + + /** + * Returns true if the supplied {@code requestMethod} potentially invalidates an entry in the + * cache. + */ + private boolean maybeRemove(String requestMethod, URI uri) { + if (requestMethod.equals("POST") || requestMethod.equals("PUT") || requestMethod.equals( + "DELETE")) { + try { + cache.remove(uriToKey(uri)); + } catch (IOException ignored) { + // The cache cannot be written. + } + return true; + } + return false; + } + + private void update(CacheResponse conditionalCacheHit, HttpURLConnection httpConnection) + throws IOException { + HttpEngine httpEngine = getHttpEngine(httpConnection); + URI uri = httpEngine.getUri(); + ResponseHeaders response = httpEngine.getResponseHeaders(); + RawHeaders varyHeaders = + httpEngine.getRequestHeaders().getHeaders().getAll(response.getVaryFields()); + Entry entry = new Entry(uri, varyHeaders, httpConnection); + DiskLruCache.Snapshot snapshot = (conditionalCacheHit instanceof EntryCacheResponse) + ? ((EntryCacheResponse) conditionalCacheHit).snapshot + : ((EntrySecureCacheResponse) conditionalCacheHit).snapshot; + DiskLruCache.Editor editor = null; + try { + editor = snapshot.edit(); // returns null if snapshot is not current + if (editor != null) { + entry.writeTo(editor); + editor.commit(); + } + } catch (IOException e) { + abortQuietly(editor); + } + } + + private void abortQuietly(DiskLruCache.Editor editor) { + // Give up because the cache cannot be written. + try { + if (editor != null) { + editor.abort(); + } + } catch (IOException ignored) { + } + } + + private HttpEngine getHttpEngine(URLConnection httpConnection) { + if (httpConnection instanceof HttpURLConnectionImpl) { + return ((HttpURLConnectionImpl) httpConnection).getHttpEngine(); + } else if (httpConnection instanceof HttpsURLConnectionImpl) { + return ((HttpsURLConnectionImpl) httpConnection).getHttpEngine(); + } else { + return null; + } + } + + /** + * Closes the cache and deletes all of its stored values. This will delete + * all files in the cache directory including files that weren't created by + * the cache. + */ + public void delete() throws IOException { + cache.delete(); + } + + public synchronized int getWriteAbortCount() { + return writeAbortCount; + } + + public synchronized int getWriteSuccessCount() { + return writeSuccessCount; + } + + public long getSize() { + return cache.size(); + } + + public long getMaxSize() { + return cache.getMaxSize(); + } + + public void flush() throws IOException { + cache.flush(); + } + + public void close() throws IOException { + cache.close(); + } + + public File getDirectory() { + return cache.getDirectory(); + } + + public boolean isClosed() { + return cache.isClosed(); + } + + private synchronized void trackResponse(ResponseSource source) { + requestCount++; + + switch (source) { + case CACHE: + hitCount++; + break; + case CONDITIONAL_CACHE: + case NETWORK: + networkCount++; + break; + } + } + + private synchronized void trackConditionalCacheHit() { + hitCount++; + } + + public synchronized int getNetworkCount() { + return networkCount; + } + + public synchronized int getHitCount() { + return hitCount; + } + + public synchronized int getRequestCount() { + return requestCount; + } + + private final class CacheRequestImpl extends CacheRequest { + private final DiskLruCache.Editor editor; + private OutputStream cacheOut; + private boolean done; + private OutputStream body; + + public CacheRequestImpl(final DiskLruCache.Editor editor) throws IOException { + this.editor = editor; + this.cacheOut = editor.newOutputStream(ENTRY_BODY); + this.body = new FilterOutputStream(cacheOut) { + @Override public void close() throws IOException { + synchronized (HttpResponseCache.this) { + if (done) { + return; + } + done = true; + writeSuccessCount++; + } + super.close(); + editor.commit(); + } + + @Override public void write(byte[] buffer, int offset, int length) throws IOException { + // Since we don't override "write(int oneByte)", we can write directly to "out" + // and avoid the inefficient implementation from the FilterOutputStream. + out.write(buffer, offset, length); + } + }; + } + + @Override public void abort() { + synchronized (HttpResponseCache.this) { + if (done) { + return; + } + done = true; + writeAbortCount++; + } + Util.closeQuietly(cacheOut); + try { + editor.abort(); + } catch (IOException ignored) { + } + } + + @Override public OutputStream getBody() throws IOException { + return body; + } + } + + private static final class Entry { + private final String uri; + private final RawHeaders varyHeaders; + private final String requestMethod; + private final RawHeaders responseHeaders; + private final String cipherSuite; + private final Certificate[] peerCertificates; + private final Certificate[] localCertificates; + + /** + * Reads an entry from an input stream. A typical entry looks like this: + *
{@code
+     *   http://google.com/foo
+     *   GET
+     *   2
+     *   Accept-Language: fr-CA
+     *   Accept-Charset: UTF-8
+     *   HTTP/1.1 200 OK
+     *   3
+     *   Content-Type: image/png
+     *   Content-Length: 100
+     *   Cache-Control: max-age=600
+     * }
+ * + *

A typical HTTPS file looks like this: + *

{@code
+     *   https://google.com/foo
+     *   GET
+     *   2
+     *   Accept-Language: fr-CA
+     *   Accept-Charset: UTF-8
+     *   HTTP/1.1 200 OK
+     *   3
+     *   Content-Type: image/png
+     *   Content-Length: 100
+     *   Cache-Control: max-age=600
+     *
+     *   AES_256_WITH_MD5
+     *   2
+     *   base64-encoded peerCertificate[0]
+     *   base64-encoded peerCertificate[1]
+     *   -1
+     * }
+ * The file is newline separated. The first two lines are the URL and + * the request method. Next is the number of HTTP Vary request header + * lines, followed by those lines. + * + *

Next is the response status line, followed by the number of HTTP + * response header lines, followed by those lines. + * + *

HTTPS responses also contain SSL session information. This begins + * with a blank line, and then a line containing the cipher suite. Next + * is the length of the peer certificate chain. These certificates are + * base64-encoded and appear each on their own line. The next line + * contains the length of the local certificate chain. These + * certificates are also base64-encoded and appear each on their own + * line. A length of -1 is used to encode a null array. + */ + public Entry(InputStream in) throws IOException { + try { + StrictLineReader reader = new StrictLineReader(in, US_ASCII); + uri = reader.readLine(); + requestMethod = reader.readLine(); + varyHeaders = new RawHeaders(); + int varyRequestHeaderLineCount = reader.readInt(); + for (int i = 0; i < varyRequestHeaderLineCount; i++) { + varyHeaders.addLine(reader.readLine()); + } + + responseHeaders = new RawHeaders(); + responseHeaders.setStatusLine(reader.readLine()); + int responseHeaderLineCount = reader.readInt(); + for (int i = 0; i < responseHeaderLineCount; i++) { + responseHeaders.addLine(reader.readLine()); + } + + if (isHttps()) { + String blank = reader.readLine(); + if (blank.length() > 0) { + throw new IOException("expected \"\" but was \"" + blank + "\""); + } + cipherSuite = reader.readLine(); + peerCertificates = readCertArray(reader); + localCertificates = readCertArray(reader); + } else { + cipherSuite = null; + peerCertificates = null; + localCertificates = null; + } + } finally { + in.close(); + } + } + + public Entry(URI uri, RawHeaders varyHeaders, HttpURLConnection httpConnection) + throws IOException { + this.uri = uri.toString(); + this.varyHeaders = varyHeaders; + this.requestMethod = httpConnection.getRequestMethod(); + this.responseHeaders = RawHeaders.fromMultimap(httpConnection.getHeaderFields(), true); + + SSLSocket sslSocket = getSslSocket(httpConnection); + if (sslSocket != null) { + cipherSuite = sslSocket.getSession().getCipherSuite(); + Certificate[] peerCertificatesNonFinal = null; + try { + peerCertificatesNonFinal = sslSocket.getSession().getPeerCertificates(); + } catch (SSLPeerUnverifiedException ignored) { + } + peerCertificates = peerCertificatesNonFinal; + localCertificates = sslSocket.getSession().getLocalCertificates(); + } else { + cipherSuite = null; + peerCertificates = null; + localCertificates = null; + } + } + + /** + * Returns the SSL socket used by {@code httpConnection} for HTTPS, nor null + * if the connection isn't using HTTPS. Since we permit redirects across + * protocols (HTTP to HTTPS or vice versa), the implementation type of the + * connection doesn't necessarily match the implementation type of its HTTP + * engine. + */ + private SSLSocket getSslSocket(HttpURLConnection httpConnection) { + HttpEngine engine = httpConnection instanceof HttpsURLConnectionImpl + ? ((HttpsURLConnectionImpl) httpConnection).getHttpEngine() + : ((HttpURLConnectionImpl) httpConnection).getHttpEngine(); + return engine instanceof HttpsEngine + ? ((HttpsEngine) engine).getSslSocket() + : null; + } + + public void writeTo(DiskLruCache.Editor editor) throws IOException { + OutputStream out = editor.newOutputStream(ENTRY_METADATA); + Writer writer = new BufferedWriter(new OutputStreamWriter(out, UTF_8)); + + writer.write(uri + '\n'); + writer.write(requestMethod + '\n'); + writer.write(Integer.toString(varyHeaders.length()) + '\n'); + for (int i = 0; i < varyHeaders.length(); i++) { + writer.write(varyHeaders.getFieldName(i) + ": " + varyHeaders.getValue(i) + '\n'); + } + + writer.write(responseHeaders.getStatusLine() + '\n'); + writer.write(Integer.toString(responseHeaders.length()) + '\n'); + for (int i = 0; i < responseHeaders.length(); i++) { + writer.write(responseHeaders.getFieldName(i) + ": " + responseHeaders.getValue(i) + '\n'); + } + + if (isHttps()) { + writer.write('\n'); + writer.write(cipherSuite + '\n'); + writeCertArray(writer, peerCertificates); + writeCertArray(writer, localCertificates); + } + writer.close(); + } + + private boolean isHttps() { + return uri.startsWith("https://"); + } + + private Certificate[] readCertArray(StrictLineReader reader) throws IOException { + int length = reader.readInt(); + if (length == -1) { + return null; + } + try { + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + Certificate[] result = new Certificate[length]; + for (int i = 0; i < result.length; i++) { + String line = reader.readLine(); + byte[] bytes = Base64.decode(line.getBytes("US-ASCII")); + result[i] = certificateFactory.generateCertificate(new ByteArrayInputStream(bytes)); + } + return result; + } catch (CertificateException e) { + throw new IOException(e.getMessage()); + } + } + + private void writeCertArray(Writer writer, Certificate[] certificates) throws IOException { + if (certificates == null) { + writer.write("-1\n"); + return; + } + try { + writer.write(Integer.toString(certificates.length) + '\n'); + for (Certificate certificate : certificates) { + byte[] bytes = certificate.getEncoded(); + String line = Base64.encode(bytes); + writer.write(line + '\n'); + } + } catch (CertificateEncodingException e) { + throw new IOException(e.getMessage()); + } + } + + public boolean matches(URI uri, String requestMethod, + Map> requestHeaders) { + return this.uri.equals(uri.toString()) + && this.requestMethod.equals(requestMethod) + && new ResponseHeaders(uri, responseHeaders).varyMatches(varyHeaders.toMultimap(false), + requestHeaders); + } + } + + /** + * Returns an input stream that reads the body of a snapshot, closing the + * snapshot when the stream is closed. + */ + private static InputStream newBodyInputStream(final DiskLruCache.Snapshot snapshot) { + return new FilterInputStream(snapshot.getInputStream(ENTRY_BODY)) { + @Override public void close() throws IOException { + snapshot.close(); + super.close(); + } + }; + } + + static class EntryCacheResponse extends CacheResponse { + private final Entry entry; + private final DiskLruCache.Snapshot snapshot; + private final InputStream in; + + public EntryCacheResponse(Entry entry, DiskLruCache.Snapshot snapshot) { + this.entry = entry; + this.snapshot = snapshot; + this.in = newBodyInputStream(snapshot); + } + + @Override public Map> getHeaders() { + return entry.responseHeaders.toMultimap(true); + } + + @Override public InputStream getBody() { + return in; + } + } + + static class EntrySecureCacheResponse extends SecureCacheResponse { + private final Entry entry; + private final DiskLruCache.Snapshot snapshot; + private final InputStream in; + + public EntrySecureCacheResponse(Entry entry, DiskLruCache.Snapshot snapshot) { + this.entry = entry; + this.snapshot = snapshot; + this.in = newBodyInputStream(snapshot); + } + + @Override public Map> getHeaders() { + return entry.responseHeaders.toMultimap(true); + } + + @Override public InputStream getBody() { + return in; + } + + @Override public String getCipherSuite() { + return entry.cipherSuite; + } + + @Override public List getServerCertificateChain() + throws SSLPeerUnverifiedException { + if (entry.peerCertificates == null || entry.peerCertificates.length == 0) { + throw new SSLPeerUnverifiedException(null); + } + return Arrays.asList(entry.peerCertificates.clone()); + } + + @Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { + if (entry.peerCertificates == null || entry.peerCertificates.length == 0) { + throw new SSLPeerUnverifiedException(null); + } + return ((X509Certificate) entry.peerCertificates[0]).getSubjectX500Principal(); + } + + @Override public List getLocalCertificateChain() { + if (entry.localCertificates == null || entry.localCertificates.length == 0) { + return null; + } + return Arrays.asList(entry.localCertificates.clone()); + } + + @Override public Principal getLocalPrincipal() { + if (entry.localCertificates == null || entry.localCertificates.length == 0) { + return null; + } + return ((X509Certificate) entry.localCertificates[0]).getSubjectX500Principal(); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/Job.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/Job.java new file mode 100755 index 0000000..1bfeb1d --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/Job.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.http.HttpAuthenticator; +import com.squareup.okhttp.internal.http.HttpEngine; +import com.squareup.okhttp.internal.http.HttpTransport; +import com.squareup.okhttp.internal.http.HttpsEngine; +import com.squareup.okhttp.internal.http.Policy; +import com.squareup.okhttp.internal.http.RawHeaders; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.ProtocolException; +import java.net.Proxy; +import java.net.URL; + +import static com.squareup.okhttp.internal.Util.getEffectivePort; +import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_MOVED_PERM; +import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_MOVED_TEMP; +import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_MULT_CHOICE; +import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_PROXY_AUTH; +import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_SEE_OTHER; +import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_TEMP_REDIRECT; +import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_UNAUTHORIZED; + +final class Job implements Runnable, Policy { + private final Dispatcher dispatcher; + private final OkHttpClient client; + private final Response.Receiver responseReceiver; + + /** The request; possibly a consequence of redirects or auth headers. */ + private Request request; + + public Job(Dispatcher dispatcher, OkHttpClient client, Request request, + Response.Receiver responseReceiver) { + this.dispatcher = dispatcher; + this.client = client; + this.request = request; + this.responseReceiver = responseReceiver; + } + + @Override public int getChunkLength() { + return request.body().contentLength() == -1 ? HttpTransport.DEFAULT_CHUNK_LENGTH : -1; + } + + @Override public long getFixedContentLength() { + return request.body().contentLength(); + } + + @Override public boolean getUseCaches() { + return false; // TODO. + } + + @Override public HttpURLConnection getHttpConnectionToCache() { + return null; + } + + @Override public URL getURL() { + return request.url(); + } + + @Override public long getIfModifiedSince() { + return 0; // For HttpURLConnection only. We let the cache drive this. + } + + @Override public boolean usingProxy() { + return false; // We let the connection decide this. + } + + @Override public void setSelectedProxy(Proxy proxy) { + // Do nothing. + } + + Object tag() { + return request.tag(); + } + + @Override public void run() { + try { + Response response = execute(); + responseReceiver.onResponse(response); + } catch (IOException e) { + responseReceiver.onFailure(new Failure.Builder() + .request(request) + .exception(e) + .build()); + } finally { + // TODO: close the response body + // TODO: release the HTTP engine (potentially multiple!) + dispatcher.finished(this); + } + } + + private Response execute() throws IOException { + Connection connection = null; + Response redirectedBy = null; + + while (true) { + HttpEngine engine = newEngine(connection); + + Request.Body body = request.body(); + if (body != null) { + MediaType contentType = body.contentType(); + if (contentType == null) throw new IllegalStateException("contentType == null"); + if (engine.getRequestHeaders().getContentType() == null) { + engine.getRequestHeaders().setContentType(contentType.toString()); + } + } + + engine.sendRequest(); + + if (body != null) { + body.writeTo(engine.getRequestBody()); + } + + engine.readResponse(); + + int responseCode = engine.getResponseCode(); + Dispatcher.RealResponseBody responseBody = new Dispatcher.RealResponseBody( + engine.getResponseHeaders(), engine.getResponseBody()); + + Response response = new Response.Builder(request, responseCode) + .rawHeaders(engine.getResponseHeaders().getHeaders()) + .body(responseBody) + .redirectedBy(redirectedBy) + .build(); + + Request redirect = processResponse(engine, response); + + if (redirect == null) { + engine.automaticallyReleaseConnectionToPool(); + return response; + } + + // TODO: fail if too many redirects + // TODO: fail if not following redirects + // TODO: release engine + + connection = sameConnection(request, redirect) ? engine.getConnection() : null; + redirectedBy = response; + request = redirect; + } + } + + HttpEngine newEngine(Connection connection) throws IOException { + String protocol = request.url().getProtocol(); + RawHeaders requestHeaders = request.rawHeaders(); + if (protocol.equals("http")) { + return new HttpEngine(client, this, request.method(), requestHeaders, connection, null); + } else if (protocol.equals("https")) { + return new HttpsEngine(client, this, request.method(), requestHeaders, connection, null); + } else { + throw new AssertionError(); + } + } + + /** + * Figures out the HTTP request to make in response to receiving {@code + * response}. This will either add authentication headers or follow + * redirects. If a follow-up is either unnecessary or not applicable, this + * returns null. + */ + private Request processResponse(HttpEngine engine, Response response) throws IOException { + Request request = response.request(); + Proxy selectedProxy = engine.getConnection() != null + ? engine.getConnection().getRoute().getProxy() + : client.getProxy(); + int responseCode = response.code(); + + switch (responseCode) { + case HTTP_PROXY_AUTH: + if (selectedProxy.type() != Proxy.Type.HTTP) { + throw new ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy"); + } + // fall-through + case HTTP_UNAUTHORIZED: + RawHeaders successorRequestHeaders = request.rawHeaders(); + boolean credentialsFound = HttpAuthenticator.processAuthHeader(client.getAuthenticator(), + response.code(), response.rawHeaders(), successorRequestHeaders, selectedProxy, + this.request.url()); + return credentialsFound + ? request.newBuilder().rawHeaders(successorRequestHeaders).build() + : null; + + case HTTP_MULT_CHOICE: + case HTTP_MOVED_PERM: + case HTTP_MOVED_TEMP: + case HTTP_SEE_OTHER: + case HTTP_TEMP_REDIRECT: + String method = request.method(); + if (responseCode == HTTP_TEMP_REDIRECT && !method.equals("GET") && !method.equals("HEAD")) { + // "If the 307 status code is received in response to a request other than GET or HEAD, + // the user agent MUST NOT automatically redirect the request" + return null; + } + + String location = response.header("Location"); + if (location == null) { + return null; + } + + URL url = new URL(request.url(), location); + if (!url.getProtocol().equals("https") && !url.getProtocol().equals("http")) { + return null; // Don't follow redirects to unsupported protocols. + } + + return this.request.newBuilder().url(url).build(); + + default: + return null; + } + } + + private boolean sameConnection(Request a, Request b) { + return a.url().getHost().equals(b.url().getHost()) + && getEffectivePort(a.url()) == getEffectivePort(b.url()) + && a.url().getProtocol().equals(b.url().getProtocol()); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/MediaType.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/MediaType.java new file mode 100755 index 0000000..2c09596 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/MediaType.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import java.nio.charset.Charset; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * An RFC 2045 Media Type, + * appropriate to describe the content type of an HTTP request or response body. + */ +public final class MediaType { + private static final String TOKEN = "([a-zA-Z0-9-!#$%&'*+.^_`{|}~]+)"; + private static final String QUOTED = "\"([^\"]*)\""; + private static final Pattern TYPE_SUBTYPE = Pattern.compile(TOKEN + "/" + TOKEN); + private static final Pattern PARAMETER = Pattern.compile( + ";\\s*" + TOKEN + "=(?:" + TOKEN + "|" + QUOTED + ")"); + + private final String mediaType; + private final String type; + private final String subtype; + private final String charset; + + private MediaType(String mediaType, String type, String subtype, String charset) { + this.mediaType = mediaType; + this.type = type; + this.subtype = subtype; + this.charset = charset; + } + + /** + * Returns a media type for {@code string}, or null if {@code string} is not a + * well-formed media type. + */ + public static MediaType parse(String string) { + Matcher typeSubtype = TYPE_SUBTYPE.matcher(string); + if (!typeSubtype.lookingAt()) return null; + String type = typeSubtype.group(1).toLowerCase(Locale.US); + String subtype = typeSubtype.group(2).toLowerCase(Locale.US); + + String charset = null; + Matcher parameter = PARAMETER.matcher(string); + for (int s = typeSubtype.end(); s < string.length(); s = parameter.end()) { + parameter.region(s, string.length()); + if (!parameter.lookingAt()) return null; // This is not a well-formed media type. + + String name = parameter.group(1); + if (name == null || !name.equalsIgnoreCase("charset")) continue; + if (charset != null) throw new IllegalArgumentException("Multiple charsets: " + string); + charset = parameter.group(2) != null + ? parameter.group(2) // Value is a token. + : parameter.group(3); // Value is a quoted string. + } + + return new MediaType(string, type, subtype, charset); + } + + /** + * Returns the high-level media type, such as "text", "image", "audio", + * "video", or "application". + */ + public String type() { + return type; + } + + /** + * Returns a specific media subtype, such as "plain" or "png", "mpeg", + * "mp4" or "xml". + */ + public String subtype() { + return subtype; + } + + /** + * Returns the charset of this media type, or null if this media type doesn't + * specify a charset. + */ + public Charset charset() { + return charset != null ? Charset.forName(charset) : null; + } + + /** + * Returns the charset of this media type, or {@code defaultValue} if this + * media type doesn't specify a charset. + */ + public Charset charset(Charset defaultValue) { + return charset != null ? Charset.forName(charset) : defaultValue; + } + + /** + * Returns the encoded media type, like "text/plain; charset=utf-8", + * appropriate for use in a Content-Type header. + */ + @Override public String toString() { + return mediaType; + } + + @Override public boolean equals(Object o) { + return o instanceof MediaType && ((MediaType) o).mediaType.equals(mediaType); + } + + @Override public int hashCode() { + return mediaType.hashCode(); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/OkAuthenticator.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/OkAuthenticator.java new file mode 100755 index 0000000..a505419 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/OkAuthenticator.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.Base64; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.Proxy; +import java.net.URL; +import java.util.List; + +/** + * Responds to authentication challenges from the remote web or proxy server by + * returning credentials. + */ +public interface OkAuthenticator { + /** + * Returns a credential that satisfies the authentication challenge made by + * {@code url}. Returns null if the challenge cannot be satisfied. This method + * is called in response to an HTTP 401 unauthorized status code sent by the + * origin server. + * + * @param challenges parsed "WWW-Authenticate" challenge headers from the HTTP + * response. + */ + Credential authenticate(Proxy proxy, URL url, List challenges) throws IOException; + + /** + * Returns a credential that satisfies the authentication challenge made by + * {@code proxy}. Returns null if the challenge cannot be satisfied. This + * method is called in response to an HTTP 401 unauthorized status code sent + * by the proxy server. + * + * @param challenges parsed "Proxy-Authenticate" challenge headers from the + * HTTP response. + */ + Credential authenticateProxy(Proxy proxy, URL url, List challenges) throws IOException; + + /** An RFC 2617 challenge. */ + public final class Challenge { + private final String scheme; + private final String realm; + + public Challenge(String scheme, String realm) { + this.scheme = scheme; + this.realm = realm; + } + + /** Returns the authentication scheme, like {@code Basic}. */ + public String getScheme() { + return scheme; + } + + /** Returns the protection space. */ + public String getRealm() { + return realm; + } + + @Override public boolean equals(Object o) { + return o instanceof Challenge + && ((Challenge) o).scheme.equals(scheme) + && ((Challenge) o).realm.equals(realm); + } + + @Override public int hashCode() { + return scheme.hashCode() + 31 * realm.hashCode(); + } + + @Override public String toString() { + return scheme + " realm=\"" + realm + "\""; + } + } + + /** An RFC 2617 credential. */ + public final class Credential { + private final String headerValue; + + private Credential(String headerValue) { + this.headerValue = headerValue; + } + + /** Returns an auth credential for the Basic scheme. */ + public static Credential basic(String userName, String password) { + try { + String usernameAndPassword = userName + ":" + password; + byte[] bytes = usernameAndPassword.getBytes("ISO-8859-1"); + String encoded = Base64.encode(bytes); + return new Credential("Basic " + encoded); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(); + } + } + + public String getHeaderValue() { + return headerValue; + } + + @Override public boolean equals(Object o) { + return o instanceof Credential && ((Credential) o).headerValue.equals(headerValue); + } + + @Override public int hashCode() { + return headerValue.hashCode(); + } + + @Override public String toString() { + return headerValue; + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/OkHttpClient.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/OkHttpClient.java new file mode 100755 index 0000000..f78592f --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/OkHttpClient.java @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2012 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.Util; +import com.squareup.okhttp.internal.http.HttpAuthenticator; +import com.squareup.okhttp.internal.http.HttpURLConnectionImpl; +import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl; +import com.squareup.okhttp.internal.http.OkResponseCacheAdapter; +import com.squareup.okhttp.internal.tls.OkHostnameVerifier; +import java.net.CookieHandler; +import java.net.HttpURLConnection; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.ResponseCache; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; + +/** Configures and creates HTTP connections. */ +public final class OkHttpClient implements URLStreamHandlerFactory { + private static final List DEFAULT_TRANSPORTS + = Util.immutableList(Arrays.asList("spdy/3", "http/1.1")); + + private final RouteDatabase routeDatabase; + private final Dispatcher dispatcher; + private Proxy proxy; + private List transports; + private ProxySelector proxySelector; + private CookieHandler cookieHandler; + private ResponseCache responseCache; + private SSLSocketFactory sslSocketFactory; + private HostnameVerifier hostnameVerifier; + private OkAuthenticator authenticator; + private ConnectionPool connectionPool; + private boolean followProtocolRedirects = true; + private int connectTimeout; + private int readTimeout; + + public OkHttpClient() { + routeDatabase = new RouteDatabase(); + dispatcher = new Dispatcher(); + } + + private OkHttpClient(OkHttpClient copyFrom) { + routeDatabase = copyFrom.routeDatabase; + dispatcher = copyFrom.dispatcher; + } + + /** + * Sets the default connect timeout for new connections. A value of 0 means no timeout. + * + * @see URLConnection#setConnectTimeout(int) + */ + public void setConnectTimeout(long timeout, TimeUnit unit) { + if (timeout < 0) { + throw new IllegalArgumentException("timeout < 0"); + } + if (unit == null) { + throw new IllegalArgumentException("unit == null"); + } + long millis = unit.toMillis(timeout); + if (millis > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Timeout too large."); + } + connectTimeout = (int) millis; + } + + /** Default connect timeout (in milliseconds). */ + public int getConnectTimeout() { + return connectTimeout; + } + + /** + * Sets the default read timeout for new connections. A value of 0 means no timeout. + * + * @see URLConnection#setReadTimeout(int) + */ + public void setReadTimeout(long timeout, TimeUnit unit) { + if (timeout < 0) { + throw new IllegalArgumentException("timeout < 0"); + } + if (unit == null) { + throw new IllegalArgumentException("unit == null"); + } + long millis = unit.toMillis(timeout); + if (millis > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Timeout too large."); + } + readTimeout = (int) millis; + } + + /** Default read timeout (in milliseconds). */ + public int getReadTimeout() { + return readTimeout; + } + + /** + * Sets the HTTP proxy that will be used by connections created by this + * client. This takes precedence over {@link #setProxySelector}, which is + * only honored when this proxy is null (which it is by default). To disable + * proxy use completely, call {@code setProxy(Proxy.NO_PROXY)}. + */ + public OkHttpClient setProxy(Proxy proxy) { + this.proxy = proxy; + return this; + } + + public Proxy getProxy() { + return proxy; + } + + /** + * Sets the proxy selection policy to be used if no {@link #setProxy proxy} + * is specified explicitly. The proxy selector may return multiple proxies; + * in that case they will be tried in sequence until a successful connection + * is established. + * + *

If unset, the {@link ProxySelector#getDefault() system-wide default} + * proxy selector will be used. + */ + public OkHttpClient setProxySelector(ProxySelector proxySelector) { + this.proxySelector = proxySelector; + return this; + } + + public ProxySelector getProxySelector() { + return proxySelector; + } + + /** + * Sets the cookie handler to be used to read outgoing cookies and write + * incoming cookies. + * + *

If unset, the {@link CookieHandler#getDefault() system-wide default} + * cookie handler will be used. + */ + public OkHttpClient setCookieHandler(CookieHandler cookieHandler) { + this.cookieHandler = cookieHandler; + return this; + } + + public CookieHandler getCookieHandler() { + return cookieHandler; + } + + /** + * Sets the response cache to be used to read and write cached responses. + * + *

If unset, the {@link ResponseCache#getDefault() system-wide default} + * response cache will be used. + */ + public OkHttpClient setResponseCache(ResponseCache responseCache) { + this.responseCache = responseCache; + return this; + } + + public ResponseCache getResponseCache() { + return responseCache; + } + + public OkResponseCache getOkResponseCache() { + if (responseCache instanceof HttpResponseCache) { + return ((HttpResponseCache) responseCache).okResponseCache; + } else if (responseCache != null) { + return new OkResponseCacheAdapter(responseCache); + } else { + return null; + } + } + + /** + * Sets the socket factory used to secure HTTPS connections. + * + *

If unset, the {@link HttpsURLConnection#getDefaultSSLSocketFactory() + * system-wide default} SSL socket factory will be used. + */ + public OkHttpClient setSslSocketFactory(SSLSocketFactory sslSocketFactory) { + this.sslSocketFactory = sslSocketFactory; + return this; + } + + public SSLSocketFactory getSslSocketFactory() { + return sslSocketFactory; + } + + /** + * Sets the verifier used to confirm that response certificates apply to + * requested hostnames for HTTPS connections. + * + *

If unset, the {@link HttpsURLConnection#getDefaultHostnameVerifier() + * system-wide default} hostname verifier will be used. + */ + public OkHttpClient setHostnameVerifier(HostnameVerifier hostnameVerifier) { + this.hostnameVerifier = hostnameVerifier; + return this; + } + + public HostnameVerifier getHostnameVerifier() { + return hostnameVerifier; + } + + /** + * Sets the authenticator used to respond to challenges from the remote web + * server or proxy server. + * + *

If unset, the {@link java.net.Authenticator#setDefault system-wide default} + * authenticator will be used. + */ + public OkHttpClient setAuthenticator(OkAuthenticator authenticator) { + this.authenticator = authenticator; + return this; + } + + public OkAuthenticator getAuthenticator() { + return authenticator; + } + + /** + * Sets the connection pool used to recycle HTTP and HTTPS connections. + * + *

If unset, the {@link ConnectionPool#getDefault() system-wide + * default} connection pool will be used. + */ + public OkHttpClient setConnectionPool(ConnectionPool connectionPool) { + this.connectionPool = connectionPool; + return this; + } + + public ConnectionPool getConnectionPool() { + return connectionPool; + } + + /** + * Configure this client to follow redirects from HTTPS to HTTP and from HTTP + * to HTTPS. + * + *

If unset, protocol redirects will be followed. This is different than + * the built-in {@code HttpURLConnection}'s default. + */ + public OkHttpClient setFollowProtocolRedirects(boolean followProtocolRedirects) { + this.followProtocolRedirects = followProtocolRedirects; + return this; + } + + public boolean getFollowProtocolRedirects() { + return followProtocolRedirects; + } + + public RouteDatabase getRoutesDatabase() { + return routeDatabase; + } + + /** + * Configure the transports used by this client to communicate with remote + * servers. By default this client will prefer the most efficient transport + * available, falling back to more ubiquitous transports. Applications should + * only call this method to avoid specific compatibility problems, such as web + * servers that behave incorrectly when SPDY is enabled. + * + *

The following transports are currently supported: + *

+ * + *

This is an evolving set. Future releases may drop + * support for transitional transports (like spdy/3), in favor of their + * successors (spdy/4 or http/2.0). The http/1.1 transport will never be + * dropped. + * + *

If multiple protocols are specified, NPN will + * be used to negotiate a transport. Future releases may use another mechanism + * (such as ALPN) + * to negotiate a transport. + * + * @param transports the transports to use, in order of preference. The list + * must contain "http/1.1". It must not contain null. + */ + public OkHttpClient setTransports(List transports) { + transports = Util.immutableList(transports); + if (!transports.contains("http/1.1")) { + throw new IllegalArgumentException("transports doesn't contain http/1.1: " + transports); + } + if (transports.contains(null)) { + throw new IllegalArgumentException("transports must not contain null"); + } + if (transports.contains("")) { + throw new IllegalArgumentException("transports contains an empty string"); + } + this.transports = transports; + return this; + } + + public List getTransports() { + return transports; + } + + /** + * Schedules {@code request} to be executed. + */ + /* OkHttp 2.0: public */ void enqueue(Request request, Response.Receiver responseReceiver) { + // Create the HttpURLConnection immediately so the enqueued job gets the current settings of + // this client. Otherwise changes to this client (socket factory, redirect policy, etc.) may + // incorrectly be reflected in the request when it is dispatched later. + dispatcher.enqueue(copyWithDefaults(), request, responseReceiver); + } + + /** + * Cancels all scheduled tasks tagged with {@code tag}. Requests that are already + * in flight might not be canceled. + */ + /* OkHttp 2.0: public */ void cancel(Object tag) { + dispatcher.cancel(tag); + } + + public HttpURLConnection open(URL url) { + return open(url, proxy); + } + + HttpURLConnection open(URL url, Proxy proxy) { + String protocol = url.getProtocol(); + OkHttpClient copy = copyWithDefaults(); + copy.proxy = proxy; + + if (protocol.equals("http")) return new HttpURLConnectionImpl(url, copy); + if (protocol.equals("https")) return new HttpsURLConnectionImpl(url, copy); + throw new IllegalArgumentException("Unexpected protocol: " + protocol); + } + + /** + * Returns a shallow copy of this OkHttpClient that uses the system-wide default for + * each field that hasn't been explicitly configured. + */ + private OkHttpClient copyWithDefaults() { + OkHttpClient result = new OkHttpClient(this); + result.proxy = proxy; + result.proxySelector = proxySelector != null ? proxySelector : ProxySelector.getDefault(); + result.cookieHandler = cookieHandler != null ? cookieHandler : CookieHandler.getDefault(); + result.responseCache = responseCache != null ? responseCache : ResponseCache.getDefault(); + result.sslSocketFactory = sslSocketFactory != null + ? sslSocketFactory + : HttpsURLConnection.getDefaultSSLSocketFactory(); + result.hostnameVerifier = hostnameVerifier != null + ? hostnameVerifier + : OkHostnameVerifier.INSTANCE; + result.authenticator = authenticator != null + ? authenticator + : HttpAuthenticator.SYSTEM_DEFAULT; + result.connectionPool = connectionPool != null ? connectionPool : ConnectionPool.getDefault(); + result.followProtocolRedirects = followProtocolRedirects; + result.transports = transports != null ? transports : DEFAULT_TRANSPORTS; + result.connectTimeout = connectTimeout; + result.readTimeout = readTimeout; + return result; + } + + /** + * Creates a URLStreamHandler as a {@link URL#setURLStreamHandlerFactory}. + * + *

This code configures OkHttp to handle all HTTP and HTTPS connections + * created with {@link URL#openConnection()}:

   {@code
+   *
+   *   OkHttpClient okHttpClient = new OkHttpClient();
+   *   URL.setURLStreamHandlerFactory(okHttpClient);
+   * }
+ */ + public URLStreamHandler createURLStreamHandler(final String protocol) { + if (!protocol.equals("http") && !protocol.equals("https")) return null; + + return new URLStreamHandler() { + @Override protected URLConnection openConnection(URL url) { + return open(url); + } + + @Override protected URLConnection openConnection(URL url, Proxy proxy) { + return open(url, proxy); + } + + @Override protected int getDefaultPort() { + if (protocol.equals("http")) return 80; + if (protocol.equals("https")) return 443; + throw new AssertionError(); + } + }; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/OkResponseCache.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/OkResponseCache.java new file mode 100755 index 0000000..ffe6f54 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/OkResponseCache.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import java.io.IOException; +import java.net.CacheRequest; +import java.net.CacheResponse; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URLConnection; +import java.util.List; +import java.util.Map; + +/** + * An extended response cache API. Unlike {@link java.net.ResponseCache}, this + * interface supports conditional caching and statistics. + * + *

Warning: Experimental OkHttp 2.0 API

+ * This class is in beta. APIs are subject to change! + */ +public interface OkResponseCache { + CacheResponse get(URI uri, String requestMethod, Map> requestHeaders) + throws IOException; + + CacheRequest put(URI uri, URLConnection urlConnection) throws IOException; + + /** Remove any cache entries for the supplied {@code uri} if the request method invalidates. */ + void maybeRemove(String requestMethod, URI uri) throws IOException; + + /** + * Handles a conditional request hit by updating the stored cache response + * with the headers from {@code httpConnection}. The cached response body is + * not updated. If the stored response has changed since {@code + * conditionalCacheHit} was returned, this does nothing. + */ + void update(CacheResponse conditionalCacheHit, HttpURLConnection connection) throws IOException; + + /** Track an conditional GET that was satisfied by this cache. */ + void trackConditionalCacheHit(); + + /** Track an HTTP response being satisfied by {@code source}. */ + void trackResponse(ResponseSource source); +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/Request.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/Request.java new file mode 100755 index 0000000..f95303e --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/Request.java @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.Util; +import com.squareup.okhttp.internal.http.RawHeaders; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Set; + +/** + * An HTTP request. Instances of this class are immutable if their {@link #body} + * is null or itself immutable. + * + *

Warning: Experimental OkHttp 2.0 API

+ * This class is in beta. APIs are subject to change! + */ +/* OkHttp 2.0: public */ final class Request { + private final URL url; + private final String method; + private final RawHeaders headers; + private final Body body; + private final Object tag; + + private Request(Builder builder) { + this.url = builder.url; + this.method = builder.method; + this.headers = new RawHeaders(builder.headers); + this.body = builder.body; + this.tag = builder.tag != null ? builder.tag : this; + } + + public URL url() { + return url; + } + + public String urlString() { + return url.toString(); + } + + public String method() { + return method; + } + + public String header(String name) { + return headers.get(name); + } + + public List headers(String name) { + return headers.values(name); + } + + public Set headerNames() { + return headers.names(); + } + + RawHeaders rawHeaders() { + return new RawHeaders(headers); + } + + public int headerCount() { + return headers.length(); + } + + public String headerName(int index) { + return headers.getFieldName(index); + } + + public String headerValue(int index) { + return headers.getValue(index); + } + + public Body body() { + return body; + } + + public Object tag() { + return tag; + } + + Builder newBuilder() { + return new Builder(url) + .method(method, body) + .rawHeaders(headers) + .tag(tag); + } + + public abstract static class Body { + /** Returns the Content-Type header for this body. */ + public abstract MediaType contentType(); + + /** + * Returns the number of bytes that will be written to {@code out} in a call + * to {@link #writeTo}, or -1 if that count is unknown. + */ + public long contentLength() { + return -1; + } + + /** Writes the content of this request to {@code out}. */ + public abstract void writeTo(OutputStream out) throws IOException; + + /** + * Returns a new request body that transmits {@code content}. If {@code + * contentType} lacks a charset, this will use UTF-8. + */ + public static Body create(MediaType contentType, String content) { + contentType = contentType.charset() != null + ? contentType + : MediaType.parse(contentType + "; charset=utf-8"); + try { + byte[] bytes = content.getBytes(contentType.charset().name()); + return create(contentType, bytes); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(); + } + } + + /** Returns a new request body that transmits {@code content}. */ + public static Body create(final MediaType contentType, final byte[] content) { + if (contentType == null) throw new NullPointerException("contentType == null"); + if (content == null) throw new NullPointerException("content == null"); + + return new Body() { + @Override public MediaType contentType() { + return contentType; + } + + @Override public long contentLength() { + return content.length; + } + + @Override public void writeTo(OutputStream out) throws IOException { + out.write(content); + } + }; + } + + /** Returns a new request body that transmits the content of {@code file}. */ + public static Body create(final MediaType contentType, final File file) { + if (contentType == null) throw new NullPointerException("contentType == null"); + if (file == null) throw new NullPointerException("content == null"); + + return new Body() { + @Override public MediaType contentType() { + return contentType; + } + + @Override public long contentLength() { + return file.length(); + } + + @Override public void writeTo(OutputStream out) throws IOException { + long length = contentLength(); + if (length == 0) return; + + InputStream in = null; + try { + in = new FileInputStream(file); + byte[] buffer = new byte[(int) Math.min(8192, length)]; + for (int c; (c = in.read(buffer)) != -1; ) { + out.write(buffer, 0, c); + } + } finally { + Util.closeQuietly(in); + } + } + }; + } + } + + public static class Builder { + private URL url; + private String method = "GET"; + private RawHeaders headers = new RawHeaders(); + private Body body; + private Object tag; + + public Builder(String url) { + url(url); + } + + public Builder(URL url) { + url(url); + } + + public Builder url(String url) { + try { + this.url = new URL(url); + return this; + } catch (MalformedURLException e) { + throw new IllegalArgumentException("Malformed URL: " + url); + } + } + + public Builder url(URL url) { + if (url == null) throw new IllegalStateException("url == null"); + this.url = url; + return this; + } + + /** + * Sets the header named {@code name} to {@code value}. If this request + * already has any headers with that name, they are all replaced. + */ + public Builder header(String name, String value) { + headers.set(name, value); + return this; + } + + /** + * Adds a header with {@code name} and {@code value}. Prefer this method for + * multiply-valued headers like "Cookie". + */ + public Builder addHeader(String name, String value) { + headers.add(name, value); + return this; + } + + Builder rawHeaders(RawHeaders rawHeaders) { + headers = new RawHeaders(rawHeaders); + return this; + } + + public Builder get() { + return method("GET", null); + } + + public Builder head() { + return method("HEAD", null); + } + + public Builder post(Body body) { + return method("POST", body); + } + + public Builder put(Body body) { + return method("PUT", body); + } + + public Builder method(String method, Body body) { + if (method == null || method.length() == 0) { + throw new IllegalArgumentException("method == null || method.length() == 0"); + } + this.method = method; + this.body = body; + return this; + } + + /** + * Attaches {@code tag} to the request. It can be used later to cancel the + * request. If the tag is unspecified or null, the request is canceled by + * using the request itself as the tag. + */ + public Builder tag(Object tag) { + this.tag = tag; + return this; + } + + public Request build() { + return new Request(this); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/Response.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/Response.java new file mode 100755 index 0000000..1e67968 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/Response.java @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.Util; +import com.squareup.okhttp.internal.http.RawHeaders; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Set; + +import static com.squareup.okhttp.internal.Util.UTF_8; + +/** + * An HTTP response. Instances of this class are not immutable: the response + * body is a one-shot value that may be consumed only once. All other properties + * are immutable. + * + *

Warning: Experimental OkHttp 2.0 API

+ * This class is in beta. APIs are subject to change! + */ +/* OkHttp 2.0: public */ final class Response { + private final Request request; + private final int code; + private final RawHeaders headers; + private final Body body; + private final Response redirectedBy; + + private Response(Builder builder) { + this.request = builder.request; + this.code = builder.code; + this.headers = new RawHeaders(builder.headers); + this.body = builder.body; + this.redirectedBy = builder.redirectedBy; + } + + /** + * The wire-level request that initiated this HTTP response. This is usually + * not the same request instance provided to the HTTP client: + *
    + *
  • It may be transformed by the HTTP client. For example, the client + * may have added its own {@code Content-Encoding} header to enable + * response compression. + *
  • It may be the request generated in response to an HTTP redirect. + * In this case the request URL may be different than the initial + * request URL. + *
+ */ + public Request request() { + return request; + } + + public int code() { + return code; + } + + public String header(String name) { + return header(name, null); + } + + public String header(String name, String defaultValue) { + String result = headers.get(name); + return result != null ? result : defaultValue; + } + + public List headers(String name) { + return headers.values(name); + } + + public Set headerNames() { + return headers.names(); + } + + public int headerCount() { + return headers.length(); + } + + public String headerName(int index) { + return headers.getFieldName(index); + } + + RawHeaders rawHeaders() { + return new RawHeaders(headers); + } + + public String headerValue(int index) { + return headers.getValue(index); + } + + public Body body() { + return body; + } + + /** + * Returns the response for the HTTP redirect that triggered this response, or + * null if this response wasn't triggered by an automatic redirect. The body + * of the returned response should not be read because it has already been + * consumed by the redirecting client. + */ + public Response redirectedBy() { + return redirectedBy; + } + + public abstract static class Body { + /** Multiple calls to {@link #charStream()} must return the same instance. */ + private Reader reader; + + /** + * Returns true if further data from this response body should be read at + * this time. For asynchronous transports like SPDY and HTTP/2.0, this will + * return false once all locally-available body bytes have been read. + * + *

Clients with many concurrent downloads can use this method to reduce + * the number of idle threads blocking on reads. See {@link + * Receiver#onResponse} for details. + */ + //

Body.ready() vs. InputStream.available()

+ // TODO: Can we fix response bodies to implement InputStream.available well? + // The deflater implementation is broken by default but we could do better. + public abstract boolean ready() throws IOException; + + public abstract MediaType contentType(); + + /** + * Returns the number of bytes in that will returned by {@link #bytes}, or + * {@link #byteStream}, or -1 if unknown. + */ + public abstract long contentLength(); + + public abstract InputStream byteStream() throws IOException; + + public final byte[] bytes() throws IOException { + long contentLength = contentLength(); + if (contentLength > Integer.MAX_VALUE) { + throw new IOException("Cannot buffer entire body for content length: " + contentLength); + } + + if (contentLength != -1) { + byte[] content = new byte[(int) contentLength]; + InputStream in = byteStream(); + Util.readFully(in, content); + if (in.read() != -1) throw new IOException("Content-Length and stream length disagree"); + return content; + + } else { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Util.copy(byteStream(), out); + return out.toByteArray(); + } + } + + /** + * Returns the response as a character stream decoded with the charset + * of the Content-Type header. If that header is either absent or lacks a + * charset, this will attempt to decode the response body as UTF-8. + */ + public final Reader charStream() throws IOException { + if (reader == null) { + reader = new InputStreamReader(byteStream(), charset()); + } + return reader; + } + + /** + * Returns the response as a string decoded with the charset of the + * Content-Type header. If that header is either absent or lacks a charset, + * this will attempt to decode the response body as UTF-8. + */ + public final String string() throws IOException { + return new String(bytes(), charset().name()); + } + + private Charset charset() { + MediaType contentType = contentType(); + return contentType != null ? contentType.charset(UTF_8) : UTF_8; + } + } + + public interface Receiver { + /** + * Called when the request could not be executed due to a connectivity + * problem or timeout. Because networks can fail during an exchange, it is + * possible that the remote server accepted the request before the failure. + */ + void onFailure(Failure failure); + + /** + * Called when the HTTP response was successfully returned by the remote + * server. The receiver may proceed to read the response body with the + * response's {@link #body} method. + * + *

Note that transport-layer success (receiving a HTTP response code, + * headers and body) does not necessarily indicate application-layer + * success: {@code response} may still indicate an unhappy HTTP response + * code like 404 or 500. + * + *

Non-blocking responses

+ * + *

Receivers do not need to block while waiting for the response body to + * download. Instead, they can get called back as data arrives. Use {@link + * Body#ready} to check if bytes should be read immediately. While there is + * data ready, read it. If there isn't, return false: receivers will be + * called back with {@code onResponse()} as additional data is downloaded. + * + *

Return true to indicate that the receiver has finished handling the + * response body. If the response body has unread data, it will be + * discarded. + * + *

When the response body has been fully consumed the returned value is + * undefined. + * + *

The current implementation of {@link Body#ready} always returns true + * when the underlying transport is HTTP/1. This results in blocking on that + * transport. For effective non-blocking your server must support SPDY or + * HTTP/2. + */ + boolean onResponse(Response response) throws IOException; + } + + public static class Builder { + private final Request request; + private final int code; + private RawHeaders headers = new RawHeaders(); + private Body body; + private Response redirectedBy; + + public Builder(Request request, int code) { + if (request == null) throw new IllegalArgumentException("request == null"); + if (code <= 0) throw new IllegalArgumentException("code <= 0"); + this.request = request; + this.code = code; + } + + /** + * Sets the header named {@code name} to {@code value}. If this request + * already has any headers with that name, they are all replaced. + */ + public Builder header(String name, String value) { + headers.set(name, value); + return this; + } + + /** + * Adds a header with {@code name} and {@code value}. Prefer this method for + * multiply-valued headers like "Set-Cookie". + */ + public Builder addHeader(String name, String value) { + headers.add(name, value); + return this; + } + + Builder rawHeaders(RawHeaders rawHeaders) { + headers = new RawHeaders(rawHeaders); + return this; + } + + public Builder body(Body body) { + this.body = body; + return this; + } + + public Builder redirectedBy(Response redirectedBy) { + this.redirectedBy = redirectedBy; + return this; + } + + public Response build() { + if (request == null) throw new IllegalStateException("Response has no request."); + if (code == -1) throw new IllegalStateException("Response has no code."); + return new Response(this); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/ResponseSource.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/ResponseSource.java new file mode 100755 index 0000000..4eca172 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/ResponseSource.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +/** The source of an HTTP response. */ +public enum ResponseSource { + + /** The response was returned from the local cache. */ + CACHE, + + /** + * The response is available in the cache but must be validated with the + * network. The cache result will be used if it is still valid; otherwise + * the network's response will be used. + */ + CONDITIONAL_CACHE, + + /** The response was returned from the network. */ + NETWORK; + + public boolean requiresConnection() { + return this == CONDITIONAL_CACHE || this == NETWORK; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/Route.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/Route.java new file mode 100755 index 0000000..4b8786d --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/Route.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import java.net.InetSocketAddress; +import java.net.Proxy; + +/** Represents the route used by a connection to reach an endpoint. */ +public class Route { + final Address address; + final Proxy proxy; + final InetSocketAddress inetSocketAddress; + final boolean modernTls; + + public Route(Address address, Proxy proxy, InetSocketAddress inetSocketAddress, + boolean modernTls) { + if (address == null) throw new NullPointerException("address == null"); + if (proxy == null) throw new NullPointerException("proxy == null"); + if (inetSocketAddress == null) throw new NullPointerException("inetSocketAddress == null"); + this.address = address; + this.proxy = proxy; + this.inetSocketAddress = inetSocketAddress; + this.modernTls = modernTls; + } + + /** Returns the {@link Address} of this route. */ + public Address getAddress() { + return address; + } + + /** + * Returns the {@link Proxy} of this route. + * + * Warning: This may be different than the proxy returned + * by {@link #getAddress}! That is the proxy that the user asked to be + * connected to; this returns the proxy that they were actually connected + * to. The two may disagree when a proxy selector selects a different proxy + * for a connection. + */ + public Proxy getProxy() { + return proxy; + } + + /** Returns the {@link InetSocketAddress} of this route. */ + public InetSocketAddress getSocketAddress() { + return inetSocketAddress; + } + + /** Returns true if this route uses modern TLS. */ + public boolean isModernTls() { + return modernTls; + } + + /** Returns a copy of this route with flipped TLS mode. */ + Route flipTlsMode() { + return new Route(address, proxy, inetSocketAddress, !modernTls); + } + + @Override public boolean equals(Object obj) { + if (obj instanceof Route) { + Route other = (Route) obj; + return (address.equals(other.address) + && proxy.equals(other.proxy) + && inetSocketAddress.equals(other.inetSocketAddress) + && modernTls == other.modernTls); + } + return false; + } + + @Override public int hashCode() { + int result = 17; + result = 31 * result + address.hashCode(); + result = 31 * result + proxy.hashCode(); + result = 31 * result + inetSocketAddress.hashCode(); + result = result + (modernTls ? (31 * result) : 0); + return result; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/RouteDatabase.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/RouteDatabase.java new file mode 100755 index 0000000..9cbeaa7 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/RouteDatabase.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.Set; +import javax.net.ssl.SSLHandshakeException; + +/** + * A blacklist of failed routes to avoid when creating a new connection to a + * target address. This is used so that OkHttp can learn from its mistakes: if + * there was a failure attempting to connect to a specific IP address, proxy + * server or TLS mode, that failure is remembered and alternate routes are + * preferred. + */ +public final class RouteDatabase { + private final Set failedRoutes = new LinkedHashSet(); + + /** Records a failure connecting to {@code failedRoute}. */ + public synchronized void failed(Route failedRoute, IOException failure) { + failedRoutes.add(failedRoute); + + if (!(failure instanceof SSLHandshakeException)) { + // If the problem was not related to SSL then it will also fail with + // a different TLS mode therefore we can be proactive about it. + failedRoutes.add(failedRoute.flipTlsMode()); + } + } + + /** Records success connecting to {@code failedRoute}. */ + public synchronized void connected(Route route) { + failedRoutes.remove(route); + } + + /** Returns true if {@code route} has failed recently and should be avoided. */ + public synchronized boolean shouldPostpone(Route route) { + return failedRoutes.contains(route); + } + + public synchronized int failedRoutesCount() { + return failedRoutes.size(); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/TunnelRequest.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/TunnelRequest.java new file mode 100755 index 0000000..5260b87 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/TunnelRequest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp; + +import com.squareup.okhttp.internal.http.RawHeaders; + +import static com.squareup.okhttp.internal.Util.getDefaultPort; + +/** + * Routing and authentication information sent to an HTTP proxy to create a + * HTTPS to an origin server. Everything in the tunnel request is sent + * unencrypted to the proxy server. + * + *

See RFC 2817, Section + * 5.2. + */ +public final class TunnelRequest { + final String host; + final int port; + final String userAgent; + final String proxyAuthorization; + + /** + * @param host the origin server's hostname. Not null. + * @param port the origin server's port, like 80 or 443. + * @param userAgent the client's user-agent. Not null. + * @param proxyAuthorization proxy authorization, or null if the proxy is + * used without an authorization header. + */ + public TunnelRequest(String host, int port, String userAgent, String proxyAuthorization) { + if (host == null) throw new NullPointerException("host == null"); + if (userAgent == null) throw new NullPointerException("userAgent == null"); + this.host = host; + this.port = port; + this.userAgent = userAgent; + this.proxyAuthorization = proxyAuthorization; + } + + /** + * If we're creating a TLS tunnel, send only the minimum set of headers. + * This avoids sending potentially sensitive data like HTTP cookies to + * the proxy unencrypted. + */ + RawHeaders getRequestHeaders() { + RawHeaders result = new RawHeaders(); + result.setRequestLine("CONNECT " + host + ":" + port + " HTTP/1.1"); + + // Always set Host and User-Agent. + result.set("Host", port == getDefaultPort("https") ? host : (host + ":" + port)); + result.set("User-Agent", userAgent); + + // Copy over the Proxy-Authorization header if it exists. + if (proxyAuthorization != null) { + result.set("Proxy-Authorization", proxyAuthorization); + } + + // Always set the Proxy-Connection to Keep-Alive for the benefit of + // HTTP/1.0 proxies like Squid. + result.set("Proxy-Connection", "Keep-Alive"); + return result; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/AbstractOutputStream.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/AbstractOutputStream.java new file mode 100755 index 0000000..78c9691 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/AbstractOutputStream.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * An output stream for an HTTP request body. + * + *

Since a single socket's output stream may be used to write multiple HTTP + * requests to the same server, subclasses should not close the socket stream. + */ +public abstract class AbstractOutputStream extends OutputStream { + protected boolean closed; + + @Override public final void write(int data) throws IOException { + write(new byte[] { (byte) data }); + } + + protected final void checkNotClosed() throws IOException { + if (closed) { + throw new IOException("stream closed"); + } + } + + /** Returns true if this stream was closed locally. */ + public boolean isClosed() { + return closed; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Base64.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Base64.java new file mode 100755 index 0000000..79cd020 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Base64.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @author Alexander Y. Kleymenov + */ + +package com.squareup.okhttp.internal; + +import java.io.UnsupportedEncodingException; + +import static com.squareup.okhttp.internal.Util.EMPTY_BYTE_ARRAY; + +/** + * Base64 encoder/decoder. + * In violation of the RFC, this encoder doesn't wrap lines at 76 columns. + */ +public final class Base64 { + private Base64() { + } + + public static byte[] decode(byte[] in) { + return decode(in, in.length); + } + + public static byte[] decode(byte[] in, int len) { + // approximate output length + int length = len / 4 * 3; + // return an empty array on empty or short input without padding + if (length == 0) { + return EMPTY_BYTE_ARRAY; + } + // temporary array + byte[] out = new byte[length]; + // number of padding characters ('=') + int pad = 0; + byte chr; + // compute the number of the padding characters + // and adjust the length of the input + for (; ; len--) { + chr = in[len - 1]; + // skip the neutral characters + if ((chr == '\n') || (chr == '\r') || (chr == ' ') || (chr == '\t')) { + continue; + } + if (chr == '=') { + pad++; + } else { + break; + } + } + // index in the output array + int outIndex = 0; + // index in the input array + int inIndex = 0; + // holds the value of the input character + int bits = 0; + // holds the value of the input quantum + int quantum = 0; + for (int i = 0; i < len; i++) { + chr = in[i]; + // skip the neutral characters + if ((chr == '\n') || (chr == '\r') || (chr == ' ') || (chr == '\t')) { + continue; + } + if ((chr >= 'A') && (chr <= 'Z')) { + // char ASCII value + // A 65 0 + // Z 90 25 (ASCII - 65) + bits = chr - 65; + } else if ((chr >= 'a') && (chr <= 'z')) { + // char ASCII value + // a 97 26 + // z 122 51 (ASCII - 71) + bits = chr - 71; + } else if ((chr >= '0') && (chr <= '9')) { + // char ASCII value + // 0 48 52 + // 9 57 61 (ASCII + 4) + bits = chr + 4; + } else if (chr == '+') { + bits = 62; + } else if (chr == '/') { + bits = 63; + } else { + return null; + } + // append the value to the quantum + quantum = (quantum << 6) | (byte) bits; + if (inIndex % 4 == 3) { + // 4 characters were read, so make the output: + out[outIndex++] = (byte) (quantum >> 16); + out[outIndex++] = (byte) (quantum >> 8); + out[outIndex++] = (byte) quantum; + } + inIndex++; + } + if (pad > 0) { + // adjust the quantum value according to the padding + quantum = quantum << (6 * pad); + // make output + out[outIndex++] = (byte) (quantum >> 16); + if (pad == 1) { + out[outIndex++] = (byte) (quantum >> 8); + } + } + // create the resulting array + byte[] result = new byte[outIndex]; + System.arraycopy(out, 0, result, 0, outIndex); + return result; + } + + private static final byte[] MAP = new byte[] { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', + '5', '6', '7', '8', '9', '+', '/' + }; + + public static String encode(byte[] in) { + int length = (in.length + 2) * 4 / 3; + byte[] out = new byte[length]; + int index = 0, end = in.length - in.length % 3; + for (int i = 0; i < end; i += 3) { + out[index++] = MAP[(in[i] & 0xff) >> 2]; + out[index++] = MAP[((in[i] & 0x03) << 4) | ((in[i + 1] & 0xff) >> 4)]; + out[index++] = MAP[((in[i + 1] & 0x0f) << 2) | ((in[i + 2] & 0xff) >> 6)]; + out[index++] = MAP[(in[i + 2] & 0x3f)]; + } + switch (in.length % 3) { + case 1: + out[index++] = MAP[(in[end] & 0xff) >> 2]; + out[index++] = MAP[(in[end] & 0x03) << 4]; + out[index++] = '='; + out[index++] = '='; + break; + case 2: + out[index++] = MAP[(in[end] & 0xff) >> 2]; + out[index++] = MAP[((in[end] & 0x03) << 4) | ((in[end + 1] & 0xff) >> 4)]; + out[index++] = MAP[((in[end + 1] & 0x0f) << 2)]; + out[index++] = '='; + break; + } + try { + return new String(out, 0, index, "US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/DiskLruCache.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/DiskLruCache.java new file mode 100755 index 0000000..f7fcb1e --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/DiskLruCache.java @@ -0,0 +1,926 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal; + +import java.io.BufferedWriter; +import java.io.Closeable; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A cache that uses a bounded amount of space on a filesystem. Each cache + * entry has a string key and a fixed number of values. Each key must match + * the regex [a-z0-9_-]{1,64}. Values are byte sequences, + * accessible as streams or files. Each value must be between {@code 0} and + * {@code Integer.MAX_VALUE} bytes in length. + * + *

The cache stores its data in a directory on the filesystem. This + * directory must be exclusive to the cache; the cache may delete or overwrite + * files from its directory. It is an error for multiple processes to use the + * same cache directory at the same time. + * + *

This cache limits the number of bytes that it will store on the + * filesystem. When the number of stored bytes exceeds the limit, the cache will + * remove entries in the background until the limit is satisfied. The limit is + * not strict: the cache may temporarily exceed it while waiting for files to be + * deleted. The limit does not include filesystem overhead or the cache + * journal so space-sensitive applications should set a conservative limit. + * + *

Clients call {@link #edit} to create or update the values of an entry. An + * entry may have only one editor at one time; if a value is not available to be + * edited then {@link #edit} will return null. + *

    + *
  • When an entry is being created it is necessary to + * supply a full set of values; the empty value should be used as a + * placeholder if necessary. + *
  • When an entry is being edited, it is not necessary + * to supply data for every value; values default to their previous + * value. + *
+ * Every {@link #edit} call must be matched by a call to {@link Editor#commit} + * or {@link Editor#abort}. Committing is atomic: a read observes the full set + * of values as they were before or after the commit, but never a mix of values. + * + *

Clients call {@link #get} to read a snapshot of an entry. The read will + * observe the value at the time that {@link #get} was called. Updates and + * removals after the call do not impact ongoing reads. + * + *

This class is tolerant of some I/O errors. If files are missing from the + * filesystem, the corresponding entries will be dropped from the cache. If + * an error occurs while writing a cache value, the edit will fail silently. + * Callers should handle other problems by catching {@code IOException} and + * responding appropriately. + */ +public final class DiskLruCache implements Closeable { + static final String JOURNAL_FILE = "journal"; + static final String JOURNAL_FILE_TEMP = "journal.tmp"; + static final String JOURNAL_FILE_BACKUP = "journal.bkp"; + static final String MAGIC = "libcore.io.DiskLruCache"; + static final String VERSION_1 = "1"; + static final long ANY_SEQUENCE_NUMBER = -1; + static final Pattern LEGAL_KEY_PATTERN = Pattern.compile("[a-z0-9_-]{1,64}"); + private static final String CLEAN = "CLEAN"; + private static final String DIRTY = "DIRTY"; + private static final String REMOVE = "REMOVE"; + private static final String READ = "READ"; + + /* + * This cache uses a journal file named "journal". A typical journal file + * looks like this: + * libcore.io.DiskLruCache + * 1 + * 100 + * 2 + * + * CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054 + * DIRTY 335c4c6028171cfddfbaae1a9c313c52 + * CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342 + * REMOVE 335c4c6028171cfddfbaae1a9c313c52 + * DIRTY 1ab96a171faeeee38496d8b330771a7a + * CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234 + * READ 335c4c6028171cfddfbaae1a9c313c52 + * READ 3400330d1dfc7f3f7f4b8d4d803dfcf6 + * + * The first five lines of the journal form its header. They are the + * constant string "libcore.io.DiskLruCache", the disk cache's version, + * the application's version, the value count, and a blank line. + * + * Each of the subsequent lines in the file is a record of the state of a + * cache entry. Each line contains space-separated values: a state, a key, + * and optional state-specific values. + * o DIRTY lines track that an entry is actively being created or updated. + * Every successful DIRTY action should be followed by a CLEAN or REMOVE + * action. DIRTY lines without a matching CLEAN or REMOVE indicate that + * temporary files may need to be deleted. + * o CLEAN lines track a cache entry that has been successfully published + * and may be read. A publish line is followed by the lengths of each of + * its values. + * o READ lines track accesses for LRU. + * o REMOVE lines track entries that have been deleted. + * + * The journal file is appended to as cache operations occur. The journal may + * occasionally be compacted by dropping redundant lines. A temporary file named + * "journal.tmp" will be used during compaction; that file should be deleted if + * it exists when the cache is opened. + */ + + private final File directory; + private final File journalFile; + private final File journalFileTmp; + private final File journalFileBackup; + private final int appVersion; + private long maxSize; + private final int valueCount; + private long size = 0; + private Writer journalWriter; + private final LinkedHashMap lruEntries = + new LinkedHashMap(0, 0.75f, true); + private int redundantOpCount; + + /** + * To differentiate between old and current snapshots, each entry is given + * a sequence number each time an edit is committed. A snapshot is stale if + * its sequence number is not equal to its entry's sequence number. + */ + private long nextSequenceNumber = 0; + + /** This cache uses a single background thread to evict entries. */ + final ThreadPoolExecutor executorService = + new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue()); + private final Callable cleanupCallable = new Callable() { + public Void call() throws Exception { + synchronized (DiskLruCache.this) { + if (journalWriter == null) { + return null; // Closed. + } + trimToSize(); + if (journalRebuildRequired()) { + rebuildJournal(); + redundantOpCount = 0; + } + } + return null; + } + }; + + private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) { + this.directory = directory; + this.appVersion = appVersion; + this.journalFile = new File(directory, JOURNAL_FILE); + this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP); + this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP); + this.valueCount = valueCount; + this.maxSize = maxSize; + } + + /** + * Opens the cache in {@code directory}, creating a cache if none exists + * there. + * + * @param directory a writable directory + * @param valueCount the number of values per cache entry. Must be positive. + * @param maxSize the maximum number of bytes this cache should use to store + * @throws IOException if reading or writing the cache directory fails + */ + public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) + throws IOException { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + if (valueCount <= 0) { + throw new IllegalArgumentException("valueCount <= 0"); + } + + // If a bkp file exists, use it instead. + File backupFile = new File(directory, JOURNAL_FILE_BACKUP); + if (backupFile.exists()) { + File journalFile = new File(directory, JOURNAL_FILE); + // If journal file also exists just delete backup file. + if (journalFile.exists()) { + backupFile.delete(); + } else { + renameTo(backupFile, journalFile, false); + } + } + + // Prefer to pick up where we left off. + DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); + if (cache.journalFile.exists()) { + try { + cache.readJournal(); + cache.processJournal(); + cache.journalWriter = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(cache.journalFile, true), Util.US_ASCII)); + return cache; + } catch (IOException journalIsCorrupt) { + Platform.get().logW("DiskLruCache " + directory + " is corrupt: " + + journalIsCorrupt.getMessage() + ", removing"); + cache.delete(); + } + } + + // Create a new empty cache. + directory.mkdirs(); + cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); + cache.rebuildJournal(); + return cache; + } + + private void readJournal() throws IOException { + StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), Util.US_ASCII); + try { + String magic = reader.readLine(); + String version = reader.readLine(); + String appVersionString = reader.readLine(); + String valueCountString = reader.readLine(); + String blank = reader.readLine(); + if (!MAGIC.equals(magic) + || !VERSION_1.equals(version) + || !Integer.toString(appVersion).equals(appVersionString) + || !Integer.toString(valueCount).equals(valueCountString) + || !"".equals(blank)) { + throw new IOException("unexpected journal header: [" + magic + ", " + version + ", " + + valueCountString + ", " + blank + "]"); + } + + int lineCount = 0; + while (true) { + try { + readJournalLine(reader.readLine()); + lineCount++; + } catch (EOFException endOfJournal) { + break; + } + } + redundantOpCount = lineCount - lruEntries.size(); + } finally { + Util.closeQuietly(reader); + } + } + + private void readJournalLine(String line) throws IOException { + int firstSpace = line.indexOf(' '); + if (firstSpace == -1) { + throw new IOException("unexpected journal line: " + line); + } + + int keyBegin = firstSpace + 1; + int secondSpace = line.indexOf(' ', keyBegin); + final String key; + if (secondSpace == -1) { + key = line.substring(keyBegin); + if (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) { + lruEntries.remove(key); + return; + } + } else { + key = line.substring(keyBegin, secondSpace); + } + + Entry entry = lruEntries.get(key); + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); + } + + if (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) { + String[] parts = line.substring(secondSpace + 1).split(" "); + entry.readable = true; + entry.currentEditor = null; + entry.setLengths(parts); + } else if (secondSpace == -1 && firstSpace == DIRTY.length() && line.startsWith(DIRTY)) { + entry.currentEditor = new Editor(entry); + } else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) { + // This work was already done by calling lruEntries.get(). + } else { + throw new IOException("unexpected journal line: " + line); + } + } + + /** + * Computes the initial size and collects garbage as a part of opening the + * cache. Dirty entries are assumed to be inconsistent and will be deleted. + */ + private void processJournal() throws IOException { + deleteIfExists(journalFileTmp); + for (Iterator i = lruEntries.values().iterator(); i.hasNext(); ) { + Entry entry = i.next(); + if (entry.currentEditor == null) { + for (int t = 0; t < valueCount; t++) { + size += entry.lengths[t]; + } + } else { + entry.currentEditor = null; + for (int t = 0; t < valueCount; t++) { + deleteIfExists(entry.getCleanFile(t)); + deleteIfExists(entry.getDirtyFile(t)); + } + i.remove(); + } + } + } + + /** + * Creates a new journal that omits redundant information. This replaces the + * current journal if it exists. + */ + private synchronized void rebuildJournal() throws IOException { + if (journalWriter != null) { + journalWriter.close(); + } + + Writer writer = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(journalFileTmp), Util.US_ASCII)); + try { + writer.write(MAGIC); + writer.write("\n"); + writer.write(VERSION_1); + writer.write("\n"); + writer.write(Integer.toString(appVersion)); + writer.write("\n"); + writer.write(Integer.toString(valueCount)); + writer.write("\n"); + writer.write("\n"); + + for (Entry entry : lruEntries.values()) { + if (entry.currentEditor != null) { + writer.write(DIRTY + ' ' + entry.key + '\n'); + } else { + writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + } + } + } finally { + writer.close(); + } + + if (journalFile.exists()) { + renameTo(journalFile, journalFileBackup, true); + } + renameTo(journalFileTmp, journalFile, false); + journalFileBackup.delete(); + + journalWriter = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(journalFile, true), Util.US_ASCII)); + } + + private static void deleteIfExists(File file) throws IOException { + if (file.exists() && !file.delete()) { + throw new IOException(); + } + } + + private static void renameTo(File from, File to, boolean deleteDestination) throws IOException { + if (deleteDestination) { + deleteIfExists(to); + } + if (!from.renameTo(to)) { + throw new IOException(); + } + } + + /** + * Returns a snapshot of the entry named {@code key}, or null if it doesn't + * exist is not currently readable. If a value is returned, it is moved to + * the head of the LRU queue. + */ + public synchronized Snapshot get(String key) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (entry == null) { + return null; + } + + if (!entry.readable) { + return null; + } + + // Open all streams eagerly to guarantee that we see a single published + // snapshot. If we opened streams lazily then the streams could come + // from different edits. + InputStream[] ins = new InputStream[valueCount]; + try { + for (int i = 0; i < valueCount; i++) { + ins[i] = new FileInputStream(entry.getCleanFile(i)); + } + } catch (FileNotFoundException e) { + // A file must have been deleted manually! + for (int i = 0; i < valueCount; i++) { + if (ins[i] != null) { + Util.closeQuietly(ins[i]); + } else { + break; + } + } + return null; + } + + redundantOpCount++; + journalWriter.append(READ + ' ' + key + '\n'); + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + + return new Snapshot(key, entry.sequenceNumber, ins, entry.lengths); + } + + /** + * Returns an editor for the entry named {@code key}, or null if another + * edit is in progress. + */ + public Editor edit(String key) throws IOException { + return edit(key, ANY_SEQUENCE_NUMBER); + } + + private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null + || entry.sequenceNumber != expectedSequenceNumber)) { + return null; // Snapshot is stale. + } + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); + } else if (entry.currentEditor != null) { + return null; // Another edit is in progress. + } + + Editor editor = new Editor(entry); + entry.currentEditor = editor; + + // Flush the journal before creating files to prevent file leaks. + journalWriter.write(DIRTY + ' ' + key + '\n'); + journalWriter.flush(); + return editor; + } + + /** Returns the directory where this cache stores its data. */ + public File getDirectory() { + return directory; + } + + /** + * Returns the maximum number of bytes that this cache should use to store + * its data. + */ + public long getMaxSize() { + return maxSize; + } + + /** + * Changes the maximum number of bytes the cache can store and queues a job + * to trim the existing store, if necessary. + */ + public synchronized void setMaxSize(long maxSize) { + this.maxSize = maxSize; + executorService.submit(cleanupCallable); + } + + /** + * Returns the number of bytes currently being used to store the values in + * this cache. This may be greater than the max size if a background + * deletion is pending. + */ + public synchronized long size() { + return size; + } + + private synchronized void completeEdit(Editor editor, boolean success) throws IOException { + Entry entry = editor.entry; + if (entry.currentEditor != editor) { + throw new IllegalStateException(); + } + + // If this edit is creating the entry for the first time, every index must have a value. + if (success && !entry.readable) { + for (int i = 0; i < valueCount; i++) { + if (!editor.written[i]) { + editor.abort(); + throw new IllegalStateException("Newly created entry didn't create value for index " + i); + } + if (!entry.getDirtyFile(i).exists()) { + editor.abort(); + return; + } + } + } + + for (int i = 0; i < valueCount; i++) { + File dirty = entry.getDirtyFile(i); + if (success) { + if (dirty.exists()) { + File clean = entry.getCleanFile(i); + dirty.renameTo(clean); + long oldLength = entry.lengths[i]; + long newLength = clean.length(); + entry.lengths[i] = newLength; + size = size - oldLength + newLength; + } + } else { + deleteIfExists(dirty); + } + } + + redundantOpCount++; + entry.currentEditor = null; + if (entry.readable | success) { + entry.readable = true; + journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + if (success) { + entry.sequenceNumber = nextSequenceNumber++; + } + } else { + lruEntries.remove(entry.key); + journalWriter.write(REMOVE + ' ' + entry.key + '\n'); + } + journalWriter.flush(); + + if (size > maxSize || journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + } + + /** + * We only rebuild the journal when it will halve the size of the journal + * and eliminate at least 2000 ops. + */ + private boolean journalRebuildRequired() { + final int redundantOpCompactThreshold = 2000; + return redundantOpCount >= redundantOpCompactThreshold // + && redundantOpCount >= lruEntries.size(); + } + + /** + * Drops the entry for {@code key} if it exists and can be removed. Entries + * actively being edited cannot be removed. + * + * @return true if an entry was removed. + */ + public synchronized boolean remove(String key) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (entry == null || entry.currentEditor != null) { + return false; + } + + for (int i = 0; i < valueCount; i++) { + File file = entry.getCleanFile(i); + if (!file.delete()) { + throw new IOException("failed to delete " + file); + } + size -= entry.lengths[i]; + entry.lengths[i] = 0; + } + + redundantOpCount++; + journalWriter.append(REMOVE + ' ' + key + '\n'); + lruEntries.remove(key); + + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } + + return true; + } + + /** Returns true if this cache has been closed. */ + public boolean isClosed() { + return journalWriter == null; + } + + private void checkNotClosed() { + if (journalWriter == null) { + throw new IllegalStateException("cache is closed"); + } + } + + /** Force buffered operations to the filesystem. */ + public synchronized void flush() throws IOException { + checkNotClosed(); + trimToSize(); + journalWriter.flush(); + } + + /** Closes this cache. Stored values will remain on the filesystem. */ + public synchronized void close() throws IOException { + if (journalWriter == null) { + return; // Already closed. + } + for (Entry entry : new ArrayList(lruEntries.values())) { + if (entry.currentEditor != null) { + entry.currentEditor.abort(); + } + } + trimToSize(); + journalWriter.close(); + journalWriter = null; + } + + private void trimToSize() throws IOException { + while (size > maxSize) { + Map.Entry toEvict = lruEntries.entrySet().iterator().next(); + remove(toEvict.getKey()); + } + } + + /** + * Closes the cache and deletes all of its stored values. This will delete + * all files in the cache directory including files that weren't created by + * the cache. + */ + public void delete() throws IOException { + close(); + Util.deleteContents(directory); + } + + private void validateKey(String key) { + Matcher matcher = LEGAL_KEY_PATTERN.matcher(key); + if (!matcher.matches()) { + throw new IllegalArgumentException("keys must match regex [a-z0-9_-]{1,64}: \"" + key + "\""); + } + } + + private static String inputStreamToString(InputStream in) throws IOException { + return Util.readFully(new InputStreamReader(in, Util.UTF_8)); + } + + /** A snapshot of the values for an entry. */ + public final class Snapshot implements Closeable { + private final String key; + private final long sequenceNumber; + private final InputStream[] ins; + private final long[] lengths; + + private Snapshot(String key, long sequenceNumber, InputStream[] ins, long[] lengths) { + this.key = key; + this.sequenceNumber = sequenceNumber; + this.ins = ins; + this.lengths = lengths; + } + + /** + * Returns an editor for this snapshot's entry, or null if either the + * entry has changed since this snapshot was created or if another edit + * is in progress. + */ + public Editor edit() throws IOException { + return DiskLruCache.this.edit(key, sequenceNumber); + } + + /** Returns the unbuffered stream with the value for {@code index}. */ + public InputStream getInputStream(int index) { + return ins[index]; + } + + /** Returns the string value for {@code index}. */ + public String getString(int index) throws IOException { + return inputStreamToString(getInputStream(index)); + } + + /** Returns the byte length of the value for {@code index}. */ + public long getLength(int index) { + return lengths[index]; + } + + public void close() { + for (InputStream in : ins) { + Util.closeQuietly(in); + } + } + } + + private static final OutputStream NULL_OUTPUT_STREAM = new OutputStream() { + @Override + public void write(int b) throws IOException { + // Eat all writes silently. Nom nom. + } + }; + + /** Edits the values for an entry. */ + public final class Editor { + private final Entry entry; + private final boolean[] written; + private boolean hasErrors; + private boolean committed; + + private Editor(Entry entry) { + this.entry = entry; + this.written = (entry.readable) ? null : new boolean[valueCount]; + } + + /** + * Returns an unbuffered input stream to read the last committed value, + * or null if no value has been committed. + */ + public InputStream newInputStream(int index) throws IOException { + synchronized (DiskLruCache.this) { + if (entry.currentEditor != this) { + throw new IllegalStateException(); + } + if (!entry.readable) { + return null; + } + try { + return new FileInputStream(entry.getCleanFile(index)); + } catch (FileNotFoundException e) { + return null; + } + } + } + + /** + * Returns the last committed value as a string, or null if no value + * has been committed. + */ + public String getString(int index) throws IOException { + InputStream in = newInputStream(index); + return in != null ? inputStreamToString(in) : null; + } + + /** + * Returns a new unbuffered output stream to write the value at + * {@code index}. If the underlying output stream encounters errors + * when writing to the filesystem, this edit will be aborted when + * {@link #commit} is called. The returned output stream does not throw + * IOExceptions. + */ + public OutputStream newOutputStream(int index) throws IOException { + synchronized (DiskLruCache.this) { + if (entry.currentEditor != this) { + throw new IllegalStateException(); + } + if (!entry.readable) { + written[index] = true; + } + File dirtyFile = entry.getDirtyFile(index); + FileOutputStream outputStream; + try { + outputStream = new FileOutputStream(dirtyFile); + } catch (FileNotFoundException e) { + // Attempt to recreate the cache directory. + directory.mkdirs(); + try { + outputStream = new FileOutputStream(dirtyFile); + } catch (FileNotFoundException e2) { + // We are unable to recover. Silently eat the writes. + return NULL_OUTPUT_STREAM; + } + } + return new FaultHidingOutputStream(outputStream); + } + } + + /** Sets the value at {@code index} to {@code value}. */ + public void set(int index, String value) throws IOException { + Writer writer = null; + try { + writer = new OutputStreamWriter(newOutputStream(index), Util.UTF_8); + writer.write(value); + } finally { + Util.closeQuietly(writer); + } + } + + /** + * Commits this edit so it is visible to readers. This releases the + * edit lock so another edit may be started on the same key. + */ + public void commit() throws IOException { + if (hasErrors) { + completeEdit(this, false); + remove(entry.key); // The previous entry is stale. + } else { + completeEdit(this, true); + } + committed = true; + } + + /** + * Aborts this edit. This releases the edit lock so another edit may be + * started on the same key. + */ + public void abort() throws IOException { + completeEdit(this, false); + } + + public void abortUnlessCommitted() { + if (!committed) { + try { + abort(); + } catch (IOException ignored) { + } + } + } + + private class FaultHidingOutputStream extends FilterOutputStream { + private FaultHidingOutputStream(OutputStream out) { + super(out); + } + + @Override public void write(int oneByte) { + try { + out.write(oneByte); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void write(byte[] buffer, int offset, int length) { + try { + out.write(buffer, offset, length); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void close() { + try { + out.close(); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override public void flush() { + try { + out.flush(); + } catch (IOException e) { + hasErrors = true; + } + } + } + } + + private final class Entry { + private final String key; + + /** Lengths of this entry's files. */ + private final long[] lengths; + + /** True if this entry has ever been published. */ + private boolean readable; + + /** The ongoing edit or null if this entry is not being edited. */ + private Editor currentEditor; + + /** The sequence number of the most recently committed edit to this entry. */ + private long sequenceNumber; + + private Entry(String key) { + this.key = key; + this.lengths = new long[valueCount]; + } + + public String getLengths() throws IOException { + StringBuilder result = new StringBuilder(); + for (long size : lengths) { + result.append(' ').append(size); + } + return result.toString(); + } + + /** Set lengths using decimal numbers like "10123". */ + private void setLengths(String[] strings) throws IOException { + if (strings.length != valueCount) { + throw invalidLengths(strings); + } + + try { + for (int i = 0; i < strings.length; i++) { + lengths[i] = Long.parseLong(strings[i]); + } + } catch (NumberFormatException e) { + throw invalidLengths(strings); + } + } + + private IOException invalidLengths(String[] strings) throws IOException { + throw new IOException("unexpected journal line: " + java.util.Arrays.toString(strings)); + } + + public File getCleanFile(int i) { + return new File(directory, key + "." + i); + } + + public File getDirtyFile(int i) { + return new File(directory, key + "." + i + ".tmp"); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Dns.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Dns.java new file mode 100755 index 0000000..69b2d37 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Dns.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2012 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Domain name service. Prefer this over {@link InetAddress#getAllByName} to + * make code more testable. + */ +public interface Dns { + Dns DEFAULT = new Dns() { + @Override public InetAddress[] getAllByName(String host) throws UnknownHostException { + return InetAddress.getAllByName(host); + } + }; + + InetAddress[] getAllByName(String host) throws UnknownHostException; +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/FaultRecoveringOutputStream.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/FaultRecoveringOutputStream.java new file mode 100755 index 0000000..c32b27a --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/FaultRecoveringOutputStream.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import static com.squareup.okhttp.internal.Util.checkOffsetAndCount; + +/** + * An output stream wrapper that recovers from failures in the underlying stream + * by replacing it with another stream. This class buffers a fixed amount of + * data under the assumption that failures occur early in a stream's life. + * If a failure occurs after the buffer has been exhausted, no recovery is + * attempted. + * + *

Subclasses must override {@link #replacementStream} which will request a + * replacement stream each time an {@link IOException} is encountered on the + * current stream. + */ +public abstract class FaultRecoveringOutputStream extends AbstractOutputStream { + private final int maxReplayBufferLength; + + /** Bytes to transmit on the replacement stream, or null if no recovery is possible. */ + private ByteArrayOutputStream replayBuffer; + private OutputStream out; + + /** + * @param maxReplayBufferLength the maximum number of successfully written + * bytes to buffer so they can be replayed in the event of an error. + * Failure recoveries are not possible once this limit has been exceeded. + */ + public FaultRecoveringOutputStream(int maxReplayBufferLength, OutputStream out) { + if (maxReplayBufferLength < 0) throw new IllegalArgumentException(); + this.maxReplayBufferLength = maxReplayBufferLength; + this.replayBuffer = new ByteArrayOutputStream(maxReplayBufferLength); + this.out = out; + } + + @Override public final void write(byte[] buffer, int offset, int count) throws IOException { + if (closed) throw new IOException("stream closed"); + checkOffsetAndCount(buffer.length, offset, count); + + while (true) { + try { + out.write(buffer, offset, count); + + if (replayBuffer != null) { + if (count + replayBuffer.size() > maxReplayBufferLength) { + // Failure recovery is no longer possible once we overflow the replay buffer. + replayBuffer = null; + } else { + // Remember the written bytes to the replay buffer. + replayBuffer.write(buffer, offset, count); + } + } + return; + } catch (IOException e) { + if (!recover(e)) throw e; + } + } + } + + @Override public final void flush() throws IOException { + if (closed) { + return; // don't throw; this stream might have been closed on the caller's behalf + } + while (true) { + try { + out.flush(); + return; + } catch (IOException e) { + if (!recover(e)) throw e; + } + } + } + + @Override public final void close() throws IOException { + if (closed) { + return; + } + while (true) { + try { + out.close(); + closed = true; + return; + } catch (IOException e) { + if (!recover(e)) throw e; + } + } + } + + /** + * Attempt to replace {@code out} with another equivalent stream. Returns true + * if a suitable replacement stream was found. + */ + private boolean recover(IOException e) { + if (replayBuffer == null) { + return false; // Can't recover because we've dropped data that we would need to replay. + } + + while (true) { + OutputStream replacementStream = null; + try { + replacementStream = replacementStream(e); + if (replacementStream == null) { + return false; + } + replaceStream(replacementStream); + return true; + } catch (IOException replacementStreamFailure) { + // The replacement was also broken. Loop to ask for another replacement. + Util.closeQuietly(replacementStream); + e = replacementStreamFailure; + } + } + } + + /** + * Returns true if errors in the underlying stream can currently be recovered. + */ + public boolean isRecoverable() { + return replayBuffer != null; + } + + /** + * Replaces the current output stream with {@code replacementStream}, writing + * any replay bytes to it if they exist. The current output stream is closed. + */ + public final void replaceStream(OutputStream replacementStream) throws IOException { + if (!isRecoverable()) { + throw new IllegalStateException(); + } + if (this.out == replacementStream) { + return; // Don't replace a stream with itself. + } + replayBuffer.writeTo(replacementStream); + Util.closeQuietly(out); + out = replacementStream; + } + + /** + * Returns a replacement output stream to recover from {@code e} thrown by the + * previous stream. Returns a new OutputStream if recovery was successful, in + * which case all previously-written data will be replayed. Returns null if + * the failure cannot be recovered. + */ + protected abstract OutputStream replacementStream(IOException e) throws IOException; +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/NamedRunnable.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/NamedRunnable.java new file mode 100755 index 0000000..992b2ae --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/NamedRunnable.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal; + +/** + * Runnable implementation which always sets its thread name. + */ +public abstract class NamedRunnable implements Runnable { + private final String name; + + public NamedRunnable(String format, Object... args) { + this.name = String.format(format, args); + } + + @Override public final void run() { + String oldName = Thread.currentThread().getName(); + Thread.currentThread().setName(name); + try { + execute(); + } finally { + Thread.currentThread().setName(oldName); + } + } + + protected abstract void execute(); +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Platform.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Platform.java new file mode 100755 index 0000000..d5884b1 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Platform.java @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2012 Square, Inc. + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import javax.net.ssl.SSLSocket; + +/** + * Access to Platform-specific features necessary for SPDY and advanced TLS. + * + *

SPDY

+ * SPDY requires a TLS extension called NPN (Next Protocol Negotiation) that's + * available in Android 4.1+ and OpenJDK 7+ (with the npn-boot extension). It + * also requires a recent version of {@code DeflaterOutputStream} that is + * public API in Java 7 and callable via reflection in Android 4.1+. + */ +public class Platform { + private static final Platform PLATFORM = findPlatform(); + + private Constructor deflaterConstructor; + + public static Platform get() { + return PLATFORM; + } + + /** Prefix used on custom headers. */ + public String getPrefix() { + return "OkHttp"; + } + + public void logW(String warning) { + System.out.println(warning); + } + + public void tagSocket(Socket socket) throws SocketException { + } + + public void untagSocket(Socket socket) throws SocketException { + } + + public URI toUriLenient(URL url) throws URISyntaxException { + return url.toURI(); // this isn't as good as the built-in toUriLenient + } + + /** + * Attempt a TLS connection with useful extensions enabled. This mode + * supports more features, but is less likely to be compatible with older + * HTTPS servers. + */ + public void enableTlsExtensions(SSLSocket socket, String uriHost) { + } + + /** + * Attempt a secure connection with basic functionality to maximize + * compatibility. Currently this uses SSL 3.0. + */ + public void supportTlsIntolerantServer(SSLSocket socket) { + socket.setEnabledProtocols(new String[] {"SSLv3"}); + } + + /** Returns the negotiated protocol, or null if no protocol was negotiated. */ + public byte[] getNpnSelectedProtocol(SSLSocket socket) { + return null; + } + + /** + * Sets client-supported protocols on a socket to send to a server. The + * protocols are only sent if the socket implementation supports NPN. + */ + public void setNpnProtocols(SSLSocket socket, byte[] npnProtocols) { + } + + public void connectSocket(Socket socket, InetSocketAddress address, + int connectTimeout) throws IOException { + socket.connect(address, connectTimeout); + } + + /** + * Returns a deflater output stream that supports SYNC_FLUSH for SPDY name + * value blocks. This throws an {@link UnsupportedOperationException} on + * Java 6 and earlier where there is no built-in API to do SYNC_FLUSH. + */ + public OutputStream newDeflaterOutputStream(OutputStream out, Deflater deflater, + boolean syncFlush) { + try { + Constructor constructor = deflaterConstructor; + if (constructor == null) { + constructor = deflaterConstructor = DeflaterOutputStream.class.getConstructor( + OutputStream.class, Deflater.class, boolean.class); + } + return constructor.newInstance(out, deflater, syncFlush); + } catch (NoSuchMethodException e) { + throw new UnsupportedOperationException("Cannot SPDY; no SYNC_FLUSH available"); + } catch (InvocationTargetException e) { + throw e.getCause() instanceof RuntimeException ? (RuntimeException) e.getCause() + : new RuntimeException(e.getCause()); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new AssertionError(); + } + } + + /** Attempt to match the host runtime to a capable Platform implementation. */ + private static Platform findPlatform() { + // Attempt to find Android 2.3+ APIs. + Class openSslSocketClass; + Method setUseSessionTickets; + Method setHostname; + try { + try { + openSslSocketClass = Class.forName("com.android.org.conscrypt.OpenSSLSocketImpl"); + } catch (ClassNotFoundException ignored) { + // Older platform before being unbundled. + openSslSocketClass = Class.forName( + "org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl"); + } + + setUseSessionTickets = openSslSocketClass.getMethod("setUseSessionTickets", boolean.class); + setHostname = openSslSocketClass.getMethod("setHostname", String.class); + + // Attempt to find Android 4.1+ APIs. + try { + Method setNpnProtocols = openSslSocketClass.getMethod("setNpnProtocols", byte[].class); + Method getNpnSelectedProtocol = openSslSocketClass.getMethod("getNpnSelectedProtocol"); + return new Android41(openSslSocketClass, setUseSessionTickets, setHostname, + setNpnProtocols, getNpnSelectedProtocol); + } catch (NoSuchMethodException ignored) { + return new Android23(openSslSocketClass, setUseSessionTickets, setHostname); + } + } catch (ClassNotFoundException ignored) { + // This isn't an Android runtime. + } catch (NoSuchMethodException ignored) { + // This isn't Android 2.3 or better. + } + + // Attempt to find the Jetty's NPN extension for OpenJDK. + try { + String npnClassName = "org.eclipse.jetty.npn.NextProtoNego"; + Class nextProtoNegoClass = Class.forName(npnClassName); + Class providerClass = Class.forName(npnClassName + "$Provider"); + Class clientProviderClass = Class.forName(npnClassName + "$ClientProvider"); + Class serverProviderClass = Class.forName(npnClassName + "$ServerProvider"); + Method putMethod = nextProtoNegoClass.getMethod("put", SSLSocket.class, providerClass); + Method getMethod = nextProtoNegoClass.getMethod("get", SSLSocket.class); + return new JdkWithJettyNpnPlatform( + putMethod, getMethod, clientProviderClass, serverProviderClass); + } catch (ClassNotFoundException ignored) { + // NPN isn't on the classpath. + } catch (NoSuchMethodException ignored) { + // The NPN version isn't what we expect. + } + + return new Platform(); + } + + /** Android version 2.3 and newer support TLS session tickets and server name indication (SNI). */ + private static class Android23 extends Platform { + protected final Class openSslSocketClass; + private final Method setUseSessionTickets; + private final Method setHostname; + + private Android23( + Class openSslSocketClass, Method setUseSessionTickets, Method setHostname) { + this.openSslSocketClass = openSslSocketClass; + this.setUseSessionTickets = setUseSessionTickets; + this.setHostname = setHostname; + } + + @Override public void connectSocket(Socket socket, InetSocketAddress address, + int connectTimeout) throws IOException { + try { + socket.connect(address, connectTimeout); + } catch (SecurityException se) { + // Before android 4.3, socket.connect could throw a SecurityException + // if opening a socket resulted in an EACCES error. + IOException ioException = new IOException("Exception in connect"); + ioException.initCause(se); + throw ioException; + } + } + + @Override public void enableTlsExtensions(SSLSocket socket, String uriHost) { + super.enableTlsExtensions(socket, uriHost); + if (openSslSocketClass.isInstance(socket)) { + // This is Android: use reflection on OpenSslSocketImpl. + try { + setUseSessionTickets.invoke(socket, true); + setHostname.invoke(socket, uriHost); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } + } + } + + /** Android version 4.1 and newer support NPN. */ + private static class Android41 extends Android23 { + private final Method setNpnProtocols; + private final Method getNpnSelectedProtocol; + + private Android41(Class openSslSocketClass, Method setUseSessionTickets, Method setHostname, + Method setNpnProtocols, Method getNpnSelectedProtocol) { + super(openSslSocketClass, setUseSessionTickets, setHostname); + this.setNpnProtocols = setNpnProtocols; + this.getNpnSelectedProtocol = getNpnSelectedProtocol; + } + + @Override public void setNpnProtocols(SSLSocket socket, byte[] npnProtocols) { + if (!openSslSocketClass.isInstance(socket)) { + return; + } + try { + setNpnProtocols.invoke(socket, new Object[] {npnProtocols}); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + @Override public byte[] getNpnSelectedProtocol(SSLSocket socket) { + if (!openSslSocketClass.isInstance(socket)) { + return null; + } + try { + return (byte[]) getNpnSelectedProtocol.invoke(socket); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } + } + + /** OpenJDK 7 plus {@code org.mortbay.jetty.npn/npn-boot} on the boot class path. */ + private static class JdkWithJettyNpnPlatform extends Platform { + private final Method getMethod; + private final Method putMethod; + private final Class clientProviderClass; + private final Class serverProviderClass; + + public JdkWithJettyNpnPlatform(Method putMethod, Method getMethod, Class clientProviderClass, + Class serverProviderClass) { + this.putMethod = putMethod; + this.getMethod = getMethod; + this.clientProviderClass = clientProviderClass; + this.serverProviderClass = serverProviderClass; + } + + @Override public void setNpnProtocols(SSLSocket socket, byte[] npnProtocols) { + try { + List strings = new ArrayList(); + for (int i = 0; i < npnProtocols.length; ) { + int length = npnProtocols[i++]; + strings.add(new String(npnProtocols, i, length, "US-ASCII")); + i += length; + } + Object provider = Proxy.newProxyInstance(Platform.class.getClassLoader(), + new Class[] {clientProviderClass, serverProviderClass}, + new JettyNpnProvider(strings)); + putMethod.invoke(null, socket, provider); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); + } catch (InvocationTargetException e) { + throw new AssertionError(e); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } + + @Override public byte[] getNpnSelectedProtocol(SSLSocket socket) { + try { + JettyNpnProvider provider = + (JettyNpnProvider) Proxy.getInvocationHandler(getMethod.invoke(null, socket)); + if (!provider.unsupported && provider.selected == null) { + Logger logger = Logger.getLogger("com.squareup.okhttp.OkHttpClient"); + logger.log(Level.INFO, + "NPN callback dropped so SPDY is disabled. " + "Is npn-boot on the boot class path?"); + return null; + } + return provider.unsupported ? null : provider.selected.getBytes("US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(); + } catch (InvocationTargetException e) { + throw new AssertionError(); + } catch (IllegalAccessException e) { + throw new AssertionError(); + } + } + } + + /** + * Handle the methods of NextProtoNego's ClientProvider and ServerProvider + * without a compile-time dependency on those interfaces. + */ + private static class JettyNpnProvider implements InvocationHandler { + private final List protocols; + private boolean unsupported; + private String selected; + + public JettyNpnProvider(List protocols) { + this.protocols = protocols; + } + + @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String methodName = method.getName(); + Class returnType = method.getReturnType(); + if (args == null) { + args = Util.EMPTY_STRING_ARRAY; + } + if (methodName.equals("supports") && boolean.class == returnType) { + return true; + } else if (methodName.equals("unsupported") && void.class == returnType) { + this.unsupported = true; + return null; + } else if (methodName.equals("protocols") && args.length == 0) { + return protocols; + } else if (methodName.equals("selectProtocol") + && String.class == returnType + && args.length == 1 + && (args[0] == null || args[0] instanceof List)) { + // TODO: use OpenSSL's algorithm which uses both lists + List serverProtocols = (List) args[0]; + this.selected = protocols.get(0); + return selected; + } else if (methodName.equals("protocolSelected") && args.length == 1) { + this.selected = (String) args[0]; + return null; + } else { + return method.invoke(this, args); + } + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/StrictLineReader.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/StrictLineReader.java new file mode 100755 index 0000000..74af6fd --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/StrictLineReader.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal; + +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; + +/** + * Buffers input from an {@link InputStream} for reading lines. + * + *

This class is used for buffered reading of lines. For purposes of this class, a line ends with + * "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated line at + * end of input is invalid and will be ignored, the caller may use {@code hasUnterminatedLine()} + * to detect it after catching the {@code EOFException}. + * + *

This class is intended for reading input that strictly consists of lines, such as line-based + * cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction + * with {@link java.io.InputStreamReader} provides similar functionality, this class uses different + * end-of-input reporting and a more restrictive definition of a line. + * + *

This class supports only charsets that encode '\r' and '\n' as a single byte with value 13 + * and 10, respectively, and the representation of no other character contains these values. + * We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1. + * The default charset is US_ASCII. + */ +public class StrictLineReader implements Closeable { + private static final byte CR = (byte) '\r'; + private static final byte LF = (byte) '\n'; + + private final InputStream in; + private final Charset charset; + + /* + * Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end + * and the data in the range [pos, end) is buffered for reading. At end of input, if there is + * an unterminated line, we set end == -1, otherwise end == pos. If the underlying + * {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1. + */ + private byte[] buf; + private int pos; + private int end; + + /** + * Constructs a new {@code LineReader} with the specified charset and the default capacity. + * + * @param in the {@code InputStream} to read data from. + * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are + * supported. + * @throws NullPointerException if {@code in} or {@code charset} is null. + * @throws IllegalArgumentException if the specified charset is not supported. + */ + public StrictLineReader(InputStream in, Charset charset) { + this(in, 8192, charset); + } + + /** + * Constructs a new {@code LineReader} with the specified capacity and charset. + * + * @param in the {@code InputStream} to read data from. + * @param capacity the capacity of the buffer. + * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are + * supported. + * @throws NullPointerException if {@code in} or {@code charset} is null. + * @throws IllegalArgumentException if {@code capacity} is negative or zero + * or the specified charset is not supported. + */ + public StrictLineReader(InputStream in, int capacity, Charset charset) { + if (in == null || charset == null) { + throw new NullPointerException(); + } + if (capacity < 0) { + throw new IllegalArgumentException("capacity <= 0"); + } + if (!(charset.equals(Util.US_ASCII))) { + throw new IllegalArgumentException("Unsupported encoding"); + } + + this.in = in; + this.charset = charset; + buf = new byte[capacity]; + } + + /** + * Closes the reader by closing the underlying {@code InputStream} and + * marking this reader as closed. + * + * @throws IOException for errors when closing the underlying {@code InputStream}. + */ + public void close() throws IOException { + synchronized (in) { + if (buf != null) { + buf = null; + in.close(); + } + } + } + + /** + * Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"}, + * this end of line marker is not included in the result. + * + * @return the next line from the input. + * @throws IOException for underlying {@code InputStream} errors. + * @throws EOFException for the end of source stream. + */ + public String readLine() throws IOException { + synchronized (in) { + if (buf == null) { + throw new IOException("LineReader is closed"); + } + + // Read more data if we are at the end of the buffered data. + // Though it's an error to read after an exception, we will let {@code fillBuf()} + // throw again if that happens; thus we need to handle end == -1 as well as end == pos. + if (pos >= end) { + fillBuf(); + } + // Try to find LF in the buffered data and return the line if successful. + for (int i = pos; i != end; ++i) { + if (buf[i] == LF) { + int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i; + String res = new String(buf, pos, lineEnd - pos, charset.name()); + pos = i + 1; + return res; + } + } + + // Let's anticipate up to 80 characters on top of those already read. + ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) { + @Override public String toString() { + int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count; + try { + return new String(buf, 0, length, charset.name()); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); // Since we control the charset this will never happen. + } + } + }; + + while (true) { + out.write(buf, pos, end - pos); + // Mark unterminated line in case fillBuf throws EOFException or IOException. + end = -1; + fillBuf(); + // Try to find LF in the buffered data and return the line if successful. + for (int i = pos; i != end; ++i) { + if (buf[i] == LF) { + if (i != pos) { + out.write(buf, pos, i - pos); + } + pos = i + 1; + return out.toString(); + } + } + } + } + } + + /** + * Read an {@code int} from a line containing its decimal representation. + * + * @return the value of the {@code int} from the next line. + * @throws IOException for underlying {@code InputStream} errors or conversion error. + * @throws EOFException for the end of source stream. + */ + public int readInt() throws IOException { + String intString = readLine(); + try { + return Integer.parseInt(intString); + } catch (NumberFormatException e) { + throw new IOException("expected an int but was \"" + intString + "\""); + } + } + + /** + * Reads new input data into the buffer. Call only with pos == end or end == -1, + * depending on the desired outcome if the function throws. + */ + private void fillBuf() throws IOException { + int result = in.read(buf, 0, buf.length); + if (result == -1) { + throw new EOFException(); + } + pos = 0; + end = result; + } +} + diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Util.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Util.java new file mode 100755 index 0000000..9c5b008 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/Util.java @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal; + +import java.io.Closeable; +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.Socket; +import java.net.ServerSocket; +import java.net.URI; +import java.net.URL; +import java.nio.ByteOrder; +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicReference; + +/** Junk drawer of utility methods. */ +public final class Util { + public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + + /** A cheap and type-safe constant for the ISO-8859-1 Charset. */ + public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); + + /** A cheap and type-safe constant for the US-ASCII Charset. */ + public static final Charset US_ASCII = Charset.forName("US-ASCII"); + + /** A cheap and type-safe constant for the UTF-8 Charset. */ + public static final Charset UTF_8 = Charset.forName("UTF-8"); + private static AtomicReference skipBuffer = new AtomicReference(); + + private static final char[] DIGITS = + { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + private Util() { + } + + public static int getEffectivePort(URI uri) { + return getEffectivePort(uri.getScheme(), uri.getPort()); + } + + public static int getEffectivePort(URL url) { + return getEffectivePort(url.getProtocol(), url.getPort()); + } + + private static int getEffectivePort(String scheme, int specifiedPort) { + return specifiedPort != -1 ? specifiedPort : getDefaultPort(scheme); + } + + public static int getDefaultPort(String scheme) { + if ("http".equalsIgnoreCase(scheme)) { + return 80; + } else if ("https".equalsIgnoreCase(scheme)) { + return 443; + } else { + return -1; + } + } + + public static void checkOffsetAndCount(int arrayLength, int offset, int count) { + if ((offset | count) < 0 || offset > arrayLength || arrayLength - offset < count) { + throw new ArrayIndexOutOfBoundsException(); + } + } + + public static void pokeInt(byte[] dst, int offset, int value, ByteOrder order) { + if (order == ByteOrder.BIG_ENDIAN) { + dst[offset++] = (byte) ((value >> 24) & 0xff); + dst[offset++] = (byte) ((value >> 16) & 0xff); + dst[offset++] = (byte) ((value >> 8) & 0xff); + dst[offset] = (byte) ((value >> 0) & 0xff); + } else { + dst[offset++] = (byte) ((value >> 0) & 0xff); + dst[offset++] = (byte) ((value >> 8) & 0xff); + dst[offset++] = (byte) ((value >> 16) & 0xff); + dst[offset] = (byte) ((value >> 24) & 0xff); + } + } + + /** Returns true if two possibly-null objects are equal. */ + public static boolean equal(Object a, Object b) { + return a == b || (a != null && a.equals(b)); + } + + /** + * Closes {@code closeable}, ignoring any checked exceptions. Does nothing + * if {@code closeable} is null. + */ + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } + + /** + * Closes {@code socket}, ignoring any checked exceptions. Does nothing if + * {@code socket} is null. + */ + public static void closeQuietly(Socket socket) { + if (socket != null) { + try { + socket.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } + + /** + * Closes {@code serverSocket}, ignoring any checked exceptions. Does nothing if + * {@code serverSocket} is null. + */ + public static void closeQuietly(ServerSocket serverSocket) { + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } + + /** + * Closes {@code a} and {@code b}. If either close fails, this completes + * the other close and rethrows the first encountered exception. + */ + public static void closeAll(Closeable a, Closeable b) throws IOException { + Throwable thrown = null; + try { + a.close(); + } catch (Throwable e) { + thrown = e; + } + try { + b.close(); + } catch (Throwable e) { + if (thrown == null) thrown = e; + } + if (thrown == null) return; + if (thrown instanceof IOException) throw (IOException) thrown; + if (thrown instanceof RuntimeException) throw (RuntimeException) thrown; + if (thrown instanceof Error) throw (Error) thrown; + throw new AssertionError(thrown); + } + + /** + * Deletes the contents of {@code dir}. Throws an IOException if any file + * could not be deleted, or if {@code dir} is not a readable directory. + */ + public static void deleteContents(File dir) throws IOException { + File[] files = dir.listFiles(); + if (files == null) { + throw new IOException("not a readable directory: " + dir); + } + for (File file : files) { + if (file.isDirectory()) { + deleteContents(file); + } + if (!file.delete()) { + throw new IOException("failed to delete file: " + file); + } + } + } + + /** + * Implements InputStream.read(int) in terms of InputStream.read(byte[], int, int). + * InputStream assumes that you implement InputStream.read(int) and provides default + * implementations of the others, but often the opposite is more efficient. + */ + public static int readSingleByte(InputStream in) throws IOException { + byte[] buffer = new byte[1]; + int result = in.read(buffer, 0, 1); + return (result != -1) ? buffer[0] & 0xff : -1; + } + + /** + * Implements OutputStream.write(int) in terms of OutputStream.write(byte[], int, int). + * OutputStream assumes that you implement OutputStream.write(int) and provides default + * implementations of the others, but often the opposite is more efficient. + */ + public static void writeSingleByte(OutputStream out, int b) throws IOException { + byte[] buffer = new byte[1]; + buffer[0] = (byte) (b & 0xff); + out.write(buffer); + } + + /** + * Fills 'dst' with bytes from 'in', throwing EOFException if insufficient bytes are available. + */ + public static void readFully(InputStream in, byte[] dst) throws IOException { + readFully(in, dst, 0, dst.length); + } + + /** + * Reads exactly 'byteCount' bytes from 'in' (into 'dst' at offset 'offset'), and throws + * EOFException if insufficient bytes are available. + * + * Used to implement {@link java.io.DataInputStream#readFully(byte[], int, int)}. + */ + public static void readFully(InputStream in, byte[] dst, int offset, int byteCount) + throws IOException { + if (byteCount == 0) { + return; + } + if (in == null) { + throw new NullPointerException("in == null"); + } + if (dst == null) { + throw new NullPointerException("dst == null"); + } + checkOffsetAndCount(dst.length, offset, byteCount); + while (byteCount > 0) { + int bytesRead = in.read(dst, offset, byteCount); + if (bytesRead < 0) { + throw new EOFException(); + } + offset += bytesRead; + byteCount -= bytesRead; + } + } + + /** Returns the remainder of 'reader' as a string, closing it when done. */ + public static String readFully(Reader reader) throws IOException { + try { + StringWriter writer = new StringWriter(); + char[] buffer = new char[1024]; + int count; + while ((count = reader.read(buffer)) != -1) { + writer.write(buffer, 0, count); + } + return writer.toString(); + } finally { + reader.close(); + } + } + + public static void skipAll(InputStream in) throws IOException { + do { + in.skip(Long.MAX_VALUE); + } while (in.read() != -1); + } + + /** + * Call {@code in.read()} repeatedly until either the stream is exhausted or + * {@code byteCount} bytes have been read. + * + *

This method reuses the skip buffer but is careful to never use it at + * the same time that another stream is using it. Otherwise streams that use + * the caller's buffer for consistency checks like CRC could be clobbered by + * other threads. A thread-local buffer is also insufficient because some + * streams may call other streams in their skip() method, also clobbering the + * buffer. + */ + public static long skipByReading(InputStream in, long byteCount) throws IOException { + if (byteCount == 0) return 0L; + + // acquire the shared skip buffer. + byte[] buffer = skipBuffer.getAndSet(null); + if (buffer == null) { + buffer = new byte[4096]; + } + + long skipped = 0; + while (skipped < byteCount) { + int toRead = (int) Math.min(byteCount - skipped, buffer.length); + int read = in.read(buffer, 0, toRead); + if (read == -1) { + break; + } + skipped += read; + if (read < toRead) { + break; + } + } + + // release the shared skip buffer. + skipBuffer.set(buffer); + + return skipped; + } + + /** + * Copies all of the bytes from {@code in} to {@code out}. Neither stream is closed. + * Returns the total number of bytes transferred. + */ + public static int copy(InputStream in, OutputStream out) throws IOException { + int total = 0; + byte[] buffer = new byte[8192]; + int c; + while ((c = in.read(buffer)) != -1) { + total += c; + out.write(buffer, 0, c); + } + return total; + } + + /** + * Returns the ASCII characters up to but not including the next "\r\n", or + * "\n". + * + * @throws java.io.EOFException if the stream is exhausted before the next newline + * character. + */ + public static String readAsciiLine(InputStream in) throws IOException { + // TODO: support UTF-8 here instead + StringBuilder result = new StringBuilder(80); + while (true) { + int c = in.read(); + if (c == -1) { + throw new EOFException(); + } else if (c == '\n') { + break; + } + + result.append((char) c); + } + int length = result.length(); + if (length > 0 && result.charAt(length - 1) == '\r') { + result.setLength(length - 1); + } + return result.toString(); + } + + /** Returns a 32 character string containing a hash of {@code s}. */ + public static String hash(String s) { + try { + MessageDigest messageDigest = MessageDigest.getInstance("MD5"); + byte[] md5bytes = messageDigest.digest(s.getBytes("UTF-8")); + return bytesToHexString(md5bytes); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError(e); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); + } + } + + private static String bytesToHexString(byte[] bytes) { + char[] digits = DIGITS; + char[] buf = new char[bytes.length * 2]; + int c = 0; + for (byte b : bytes) { + buf[c++] = digits[(b >> 4) & 0xf]; + buf[c++] = digits[b & 0xf]; + } + return new String(buf); + } + + /** Returns an immutable copy of {@code list}. */ + public static List immutableList(List list) { + return Collections.unmodifiableList(new ArrayList(list)); + } + + public static ThreadFactory daemonThreadFactory(final String name) { + return new ThreadFactory() { + @Override public Thread newThread(Runnable runnable) { + Thread result = new Thread(runnable, name); + result.setDaemon(true); + return result; + } + }; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/AbstractHttpInputStream.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/AbstractHttpInputStream.java new file mode 100755 index 0000000..a5d39b3 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/AbstractHttpInputStream.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.internal.Util; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.CacheRequest; + +/** + * An input stream for the body of an HTTP response. + * + *

Since a single socket's input stream may be used to read multiple HTTP + * responses from the same server, subclasses shouldn't close the socket stream. + * + *

A side effect of reading an HTTP response is that the response cache + * is populated. If the stream is closed early, that cache entry will be + * invalidated. + */ +abstract class AbstractHttpInputStream extends InputStream { + protected final InputStream in; + protected final HttpEngine httpEngine; + private final CacheRequest cacheRequest; + private final OutputStream cacheBody; + protected boolean closed; + + AbstractHttpInputStream(InputStream in, HttpEngine httpEngine, CacheRequest cacheRequest) + throws IOException { + this.in = in; + this.httpEngine = httpEngine; + + OutputStream cacheBody = cacheRequest != null ? cacheRequest.getBody() : null; + + // some apps return a null body; for compatibility we treat that like a null cache request + if (cacheBody == null) { + cacheRequest = null; + } + + this.cacheBody = cacheBody; + this.cacheRequest = cacheRequest; + } + + /** + * read() is implemented using read(byte[], int, int) so subclasses only + * need to override the latter. + */ + @Override public final int read() throws IOException { + return Util.readSingleByte(this); + } + + protected final void checkNotClosed() throws IOException { + if (closed) { + throw new IOException("stream closed"); + } + } + + protected final void cacheWrite(byte[] buffer, int offset, int count) throws IOException { + if (cacheBody != null) { + cacheBody.write(buffer, offset, count); + } + } + + /** + * Closes the cache entry and makes the socket available for reuse. This + * should be invoked when the end of the body has been reached. + */ + protected final void endOfInput() throws IOException { + if (cacheRequest != null) { + cacheBody.close(); + } + httpEngine.release(false); + } + + /** + * Calls abort on the cache entry and disconnects the socket. This + * should be invoked when the connection is closed unexpectedly to + * invalidate the cache entry and to prevent the HTTP connection from + * being reused. HTTP messages are sent in serial so whenever a message + * cannot be read to completion, subsequent messages cannot be read + * either and the connection must be discarded. + * + *

An earlier implementation skipped the remaining bytes, but this + * requires that the entire transfer be completed. If the intention was + * to cancel the transfer, closing the connection is the only solution. + */ + protected final void unexpectedEndOfInput() { + if (cacheRequest != null) { + cacheRequest.abort(); + } + httpEngine.release(true); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HeaderParser.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HeaderParser.java new file mode 100755 index 0000000..d5f0f4f --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HeaderParser.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +final class HeaderParser { + + public interface CacheControlHandler { + void handle(String directive, String parameter); + } + + /** Parse a comma-separated list of cache control header values. */ + public static void parseCacheControl(String value, CacheControlHandler handler) { + int pos = 0; + while (pos < value.length()) { + int tokenStart = pos; + pos = skipUntil(value, pos, "=,;"); + String directive = value.substring(tokenStart, pos).trim(); + + if (pos == value.length() || value.charAt(pos) == ',' || value.charAt(pos) == ';') { + pos++; // consume ',' or ';' (if necessary) + handler.handle(directive, null); + continue; + } + + pos++; // consume '=' + pos = skipWhitespace(value, pos); + + String parameter; + + // quoted string + if (pos < value.length() && value.charAt(pos) == '\"') { + pos++; // consume '"' open quote + int parameterStart = pos; + pos = skipUntil(value, pos, "\""); + parameter = value.substring(parameterStart, pos); + pos++; // consume '"' close quote (if necessary) + + // unquoted string + } else { + int parameterStart = pos; + pos = skipUntil(value, pos, ",;"); + parameter = value.substring(parameterStart, pos).trim(); + } + + handler.handle(directive, parameter); + } + } + + /** + * Returns the next index in {@code input} at or after {@code pos} that + * contains a character from {@code characters}. Returns the input length if + * none of the requested characters can be found. + */ + public static int skipUntil(String input, int pos, String characters) { + for (; pos < input.length(); pos++) { + if (characters.indexOf(input.charAt(pos)) != -1) { + break; + } + } + return pos; + } + + /** + * Returns the next non-whitespace character in {@code input} that is white + * space. Result is undefined if input contains newline characters. + */ + public static int skipWhitespace(String input, int pos) { + for (; pos < input.length(); pos++) { + char c = input.charAt(pos); + if (c != ' ' && c != '\t') { + break; + } + } + return pos; + } + + /** + * Returns {@code value} as a positive integer, or 0 if it is negative, or + * -1 if it cannot be parsed. + */ + public static int parseSeconds(String value) { + try { + long seconds = Long.parseLong(value); + if (seconds > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else if (seconds < 0) { + return 0; + } else { + return (int) seconds; + } + } catch (NumberFormatException e) { + return -1; + } + } + + private HeaderParser() { + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpAuthenticator.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpAuthenticator.java new file mode 100755 index 0000000..1ad3689 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpAuthenticator.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2012 Square, Inc. + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.OkAuthenticator; +import com.squareup.okhttp.OkAuthenticator.Challenge; +import java.io.IOException; +import java.net.Authenticator; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.Proxy; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import static com.squareup.okhttp.OkAuthenticator.Credential; +import static java.net.HttpURLConnection.HTTP_PROXY_AUTH; +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; + +/** Handles HTTP authentication headers from origin and proxy servers. */ +public final class HttpAuthenticator { + /** Uses the global authenticator to get the password. */ + public static final OkAuthenticator SYSTEM_DEFAULT = new OkAuthenticator() { + @Override public Credential authenticate( + Proxy proxy, URL url, List challenges) throws IOException { + for (Challenge challenge : challenges) { + if (!"Basic".equalsIgnoreCase(challenge.getScheme())) { + continue; + } + + PasswordAuthentication auth = Authenticator.requestPasswordAuthentication(url.getHost(), + getConnectToInetAddress(proxy, url), url.getPort(), url.getProtocol(), + challenge.getRealm(), challenge.getScheme(), url, Authenticator.RequestorType.SERVER); + if (auth != null) { + return Credential.basic(auth.getUserName(), new String(auth.getPassword())); + } + } + return null; + } + + @Override public Credential authenticateProxy( + Proxy proxy, URL url, List challenges) throws IOException { + for (Challenge challenge : challenges) { + if (!"Basic".equalsIgnoreCase(challenge.getScheme())) { + continue; + } + + InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address(); + PasswordAuthentication auth = Authenticator.requestPasswordAuthentication( + proxyAddress.getHostName(), getConnectToInetAddress(proxy, url), proxyAddress.getPort(), + url.getProtocol(), challenge.getRealm(), challenge.getScheme(), url, + Authenticator.RequestorType.PROXY); + if (auth != null) { + return Credential.basic(auth.getUserName(), new String(auth.getPassword())); + } + } + return null; + } + + private InetAddress getConnectToInetAddress(Proxy proxy, URL url) throws IOException { + return (proxy != null && proxy.type() != Proxy.Type.DIRECT) + ? ((InetSocketAddress) proxy.address()).getAddress() + : InetAddress.getByName(url.getHost()); + } + }; + + private HttpAuthenticator() { + } + + /** + * React to a failed authorization response by looking up new credentials. + * + * @return true if credentials have been added to successorRequestHeaders + * and another request should be attempted. + */ + public static boolean processAuthHeader(OkAuthenticator authenticator, int responseCode, + RawHeaders responseHeaders, RawHeaders successorRequestHeaders, Proxy proxy, URL url) + throws IOException { + String responseField; + String requestField; + if (responseCode == HTTP_UNAUTHORIZED) { + responseField = "WWW-Authenticate"; + requestField = "Authorization"; + } else if (responseCode == HTTP_PROXY_AUTH) { + responseField = "Proxy-Authenticate"; + requestField = "Proxy-Authorization"; + } else { + throw new IllegalArgumentException(); // TODO: ProtocolException? + } + List challenges = parseChallenges(responseHeaders, responseField); + if (challenges.isEmpty()) { + return false; // Could not find a challenge so end the request cycle. + } + Credential credential = responseHeaders.getResponseCode() == HTTP_PROXY_AUTH + ? authenticator.authenticateProxy(proxy, url, challenges) + : authenticator.authenticate(proxy, url, challenges); + if (credential == null) { + return false; // Could not satisfy the challenge so end the request cycle. + } + // Add authorization credentials, bypassing the already-connected check. + successorRequestHeaders.set(requestField, credential.getHeaderValue()); + return true; + } + + /** + * Parse RFC 2617 challenges. This API is only interested in the scheme + * name and realm. + */ + private static List parseChallenges(RawHeaders responseHeaders, + String challengeHeader) { + // auth-scheme = token + // auth-param = token "=" ( token | quoted-string ) + // challenge = auth-scheme 1*SP 1#auth-param + // realm = "realm" "=" realm-value + // realm-value = quoted-string + List result = new ArrayList(); + for (int h = 0; h < responseHeaders.length(); h++) { + if (!challengeHeader.equalsIgnoreCase(responseHeaders.getFieldName(h))) { + continue; + } + String value = responseHeaders.getValue(h); + int pos = 0; + while (pos < value.length()) { + int tokenStart = pos; + pos = HeaderParser.skipUntil(value, pos, " "); + + String scheme = value.substring(tokenStart, pos).trim(); + pos = HeaderParser.skipWhitespace(value, pos); + + // TODO: This currently only handles schemes with a 'realm' parameter; + // It needs to be fixed to handle any scheme and any parameters + // http://code.google.com/p/android/issues/detail?id=11140 + + if (!value.regionMatches(true, pos, "realm=\"", 0, "realm=\"".length())) { + break; // Unexpected challenge parameter; give up! + } + + pos += "realm=\"".length(); + int realmStart = pos; + pos = HeaderParser.skipUntil(value, pos, "\""); + String realm = value.substring(realmStart, pos); + pos++; // Consume '"' close quote. + pos = HeaderParser.skipUntil(value, pos, ","); + pos++; // Consume ',' comma. + pos = HeaderParser.skipWhitespace(value, pos); + result.add(new Challenge(scheme, realm)); + } + } + return result; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpDate.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpDate.java new file mode 100755 index 0000000..b4d2c7c --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpDate.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +/** + * Best-effort parser for HTTP dates. + */ +final class HttpDate { + + /** + * Most websites serve cookies in the blessed format. Eagerly create the parser to ensure such + * cookies are on the fast path. + */ + private static final ThreadLocal STANDARD_DATE_FORMAT = + new ThreadLocal() { + @Override protected DateFormat initialValue() { + DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); + rfc1123.setTimeZone(TimeZone.getTimeZone("GMT")); + return rfc1123; + } + }; + + /** If we fail to parse a date in a non-standard format, try each of these formats in sequence. */ + private static final String[] BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS = new String[] { + "EEEE, dd-MMM-yy HH:mm:ss zzz", // RFC 1036 + "EEE MMM d HH:mm:ss yyyy", // ANSI C asctime() + "EEE, dd-MMM-yyyy HH:mm:ss z", "EEE, dd-MMM-yyyy HH-mm-ss z", "EEE, dd MMM yy HH:mm:ss z", + "EEE dd-MMM-yyyy HH:mm:ss z", "EEE dd MMM yyyy HH:mm:ss z", "EEE dd-MMM-yyyy HH-mm-ss z", + "EEE dd-MMM-yy HH:mm:ss z", "EEE dd MMM yy HH:mm:ss z", "EEE,dd-MMM-yy HH:mm:ss z", + "EEE,dd-MMM-yyyy HH:mm:ss z", "EEE, dd-MM-yyyy HH:mm:ss z", + + /* RI bug 6641315 claims a cookie of this format was once served by www.yahoo.com */ + "EEE MMM d yyyy HH:mm:ss z", }; + + private static final DateFormat[] BROWSER_COMPATIBLE_DATE_FORMATS = + new DateFormat[BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS.length]; + + /** Returns the date for {@code value}. Returns null if the value couldn't be parsed. */ + public static Date parse(String value) { + try { + return STANDARD_DATE_FORMAT.get().parse(value); + } catch (ParseException ignored) { + } + synchronized (BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS) { + for (int i = 0, count = BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS.length; i < count; i++) { + DateFormat format = BROWSER_COMPATIBLE_DATE_FORMATS[i]; + if (format == null) { + format = new SimpleDateFormat(BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS[i], Locale.US); + BROWSER_COMPATIBLE_DATE_FORMATS[i] = format; + } + try { + return format.parse(value); + } catch (ParseException ignored) { + } + } + } + return null; + } + + /** Returns the string for {@code value}. */ + public static String format(Date value) { + return STANDARD_DATE_FORMAT.get().format(value); + } + + private HttpDate() { + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpEngine.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpEngine.java new file mode 100755 index 0000000..4a2dad4 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpEngine.java @@ -0,0 +1,686 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.Address; +import com.squareup.okhttp.Connection; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.OkResponseCache; +import com.squareup.okhttp.ResponseSource; +import com.squareup.okhttp.TunnelRequest; +import com.squareup.okhttp.internal.Dns; +import com.squareup.okhttp.internal.Platform; +import com.squareup.okhttp.internal.Util; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.CacheRequest; +import java.net.CacheResponse; +import java.net.CookieHandler; +import java.net.HttpURLConnection; +import java.net.Proxy; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.UnknownHostException; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.GZIPInputStream; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSocketFactory; + +import static com.squareup.okhttp.internal.Util.EMPTY_BYTE_ARRAY; +import static com.squareup.okhttp.internal.Util.getDefaultPort; +import static com.squareup.okhttp.internal.Util.getEffectivePort; + +/** + * Handles a single HTTP request/response pair. Each HTTP engine follows this + * lifecycle: + *

    + *
  1. It is created. + *
  2. The HTTP request message is sent with sendRequest(). Once the request + * is sent it is an error to modify the request headers. After + * sendRequest() has been called the request body can be written to if + * it exists. + *
  3. The HTTP response message is read with readResponse(). After the + * response has been read the response headers and body can be read. + * All responses have a response body input stream, though in some + * instances this stream is empty. + *
+ * + *

The request and response may be served by the HTTP response cache, by the + * network, or by both in the event of a conditional GET. + * + *

This class may hold a socket connection that needs to be released or + * recycled. By default, this socket connection is held when the last byte of + * the response is consumed. To release the connection when it is no longer + * required, use {@link #automaticallyReleaseConnectionToPool()}. + */ +public class HttpEngine { + private static final CacheResponse GATEWAY_TIMEOUT_RESPONSE = new CacheResponse() { + @Override public Map> getHeaders() throws IOException { + Map> result = new HashMap>(); + result.put(null, Collections.singletonList("HTTP/1.1 504 Gateway Timeout")); + return result; + } + @Override public InputStream getBody() throws IOException { + return new ByteArrayInputStream(EMPTY_BYTE_ARRAY); + } + }; + public static final int HTTP_CONTINUE = 100; + + protected final Policy policy; + protected final OkHttpClient client; + + protected final String method; + + private ResponseSource responseSource; + + protected Connection connection; + protected RouteSelector routeSelector; + private OutputStream requestBodyOut; + + private Transport transport; + + private InputStream responseTransferIn; + private InputStream responseBodyIn; + + private CacheResponse cacheResponse; + private CacheRequest cacheRequest; + + /** The time when the request headers were written, or -1 if they haven't been written yet. */ + long sentRequestMillis = -1; + + /** Whether the connection has been established. */ + boolean connected; + + /** + * True if this client added an "Accept-Encoding: gzip" header field and is + * therefore responsible for also decompressing the transfer stream. + */ + private boolean transparentGzip; + + final URI uri; + + final RequestHeaders requestHeaders; + + /** Null until a response is received from the network or the cache. */ + ResponseHeaders responseHeaders; + + // The cache response currently being validated on a conditional get. Null + // if the cached response doesn't exist or doesn't need validation. If the + // conditional get succeeds, these will be used for the response headers and + // body. If it fails, these be closed and set to null. + private ResponseHeaders cachedResponseHeaders; + private InputStream cachedResponseBody; + + /** + * True if the socket connection should be released to the connection pool + * when the response has been fully read. + */ + private boolean automaticallyReleaseConnectionToPool; + + /** True if the socket connection is no longer needed by this engine. */ + private boolean connectionReleased; + + /** + * @param requestHeaders the client's supplied request headers. This class + * creates a private copy that it can mutate. + * @param connection the connection used for an intermediate response + * immediately prior to this request/response pair, such as a same-host + * redirect. This engine assumes ownership of the connection and must + * release it when it is unneeded. + */ + public HttpEngine(OkHttpClient client, Policy policy, String method, RawHeaders requestHeaders, + Connection connection, RetryableOutputStream requestBodyOut) throws IOException { + this.client = client; + this.policy = policy; + this.method = method; + this.connection = connection; + this.requestBodyOut = requestBodyOut; + + try { + uri = Platform.get().toUriLenient(policy.getURL()); + } catch (URISyntaxException e) { + throw new IOException(e.getMessage()); + } + + this.requestHeaders = new RequestHeaders(uri, new RawHeaders(requestHeaders)); + } + + public URI getUri() { + return uri; + } + + /** + * Figures out what the response source will be, and opens a socket to that + * source if necessary. Prepares the request headers and gets ready to start + * writing the request body if it exists. + */ + public final void sendRequest() throws IOException { + if (responseSource != null) { + return; + } + + prepareRawRequestHeaders(); + initResponseSource(); + OkResponseCache responseCache = client.getOkResponseCache(); + if (responseCache != null) { + responseCache.trackResponse(responseSource); + } + + // The raw response source may require the network, but the request + // headers may forbid network use. In that case, dispose of the network + // response and use a GATEWAY_TIMEOUT response instead, as specified + // by http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4. + if (requestHeaders.isOnlyIfCached() && responseSource.requiresConnection()) { + if (responseSource == ResponseSource.CONDITIONAL_CACHE) { + Util.closeQuietly(cachedResponseBody); + } + this.responseSource = ResponseSource.CACHE; + this.cacheResponse = GATEWAY_TIMEOUT_RESPONSE; + RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(cacheResponse.getHeaders(), true); + setResponse(new ResponseHeaders(uri, rawResponseHeaders), cacheResponse.getBody()); + } + + if (responseSource.requiresConnection()) { + sendSocketRequest(); + } else if (connection != null) { + client.getConnectionPool().recycle(connection); + connection = null; + } + } + + /** + * Initialize the source for this response. It may be corrected later if the + * request headers forbids network use. + */ + private void initResponseSource() throws IOException { + responseSource = ResponseSource.NETWORK; + if (!policy.getUseCaches()) return; + + OkResponseCache responseCache = client.getOkResponseCache(); + if (responseCache == null) return; + + CacheResponse candidate = responseCache.get( + uri, method, requestHeaders.getHeaders().toMultimap(false)); + if (candidate == null) return; + + Map> responseHeadersMap = candidate.getHeaders(); + cachedResponseBody = candidate.getBody(); + if (!acceptCacheResponseType(candidate) + || responseHeadersMap == null + || cachedResponseBody == null) { + Util.closeQuietly(cachedResponseBody); + return; + } + + RawHeaders rawResponseHeaders = RawHeaders.fromMultimap(responseHeadersMap, true); + cachedResponseHeaders = new ResponseHeaders(uri, rawResponseHeaders); + long now = System.currentTimeMillis(); + this.responseSource = cachedResponseHeaders.chooseResponseSource(now, requestHeaders); + if (responseSource == ResponseSource.CACHE) { + this.cacheResponse = candidate; + setResponse(cachedResponseHeaders, cachedResponseBody); + } else if (responseSource == ResponseSource.CONDITIONAL_CACHE) { + this.cacheResponse = candidate; + } else if (responseSource == ResponseSource.NETWORK) { + Util.closeQuietly(cachedResponseBody); + } else { + throw new AssertionError(); + } + } + + private void sendSocketRequest() throws IOException { + if (connection == null) { + connect(); + } + + if (transport != null) { + throw new IllegalStateException(); + } + + transport = (Transport) connection.newTransport(this); + + if (hasRequestBody() && requestBodyOut == null) { + // Create a request body if we don't have one already. We'll already + // have one if we're retrying a failed POST. + requestBodyOut = transport.createRequestBody(); + } + } + + /** Connect to the origin server either directly or via a proxy. */ + protected final void connect() throws IOException { + if (connection != null) { + return; + } + if (routeSelector == null) { + String uriHost = uri.getHost(); + if (uriHost == null) { + throw new UnknownHostException(uri.toString()); + } + SSLSocketFactory sslSocketFactory = null; + HostnameVerifier hostnameVerifier = null; + if (uri.getScheme().equalsIgnoreCase("https")) { + sslSocketFactory = client.getSslSocketFactory(); + hostnameVerifier = client.getHostnameVerifier(); + } + Address address = new Address(uriHost, getEffectivePort(uri), sslSocketFactory, + hostnameVerifier, client.getAuthenticator(), client.getProxy(), client.getTransports()); + routeSelector = new RouteSelector(address, uri, client.getProxySelector(), + client.getConnectionPool(), Dns.DEFAULT, client.getRoutesDatabase()); + } + connection = routeSelector.next(method); + if (!connection.isConnected()) { + connection.connect(client.getConnectTimeout(), client.getReadTimeout(), getTunnelConfig()); + client.getConnectionPool().maybeShare(connection); + client.getRoutesDatabase().connected(connection.getRoute()); + } else if (!connection.isSpdy()) { + connection.updateReadTimeout(client.getReadTimeout()); + } + connected(connection); + if (connection.getRoute().getProxy() != client.getProxy()) { + // Update the request line if the proxy changed; it may need a host name. + requestHeaders.getHeaders().setRequestLine(getRequestLine()); + } + } + + /** + * Called after a socket connection has been created or retrieved from the + * pool. Subclasses use this hook to get a reference to the TLS data. + */ + protected void connected(Connection connection) { + policy.setSelectedProxy(connection.getRoute().getProxy()); + connected = true; + } + + /** + * Called immediately before the transport transmits HTTP request headers. + * This is used to observe the sent time should the request be cached. + */ + public void writingRequestHeaders() { + if (sentRequestMillis != -1) { + throw new IllegalStateException(); + } + sentRequestMillis = System.currentTimeMillis(); + } + + /** + * @param body the response body, or null if it doesn't exist or isn't + * available. + */ + private void setResponse(ResponseHeaders headers, InputStream body) throws IOException { + if (this.responseBodyIn != null) { + throw new IllegalStateException(); + } + this.responseHeaders = headers; + if (body != null) { + initContentStream(body); + } + } + + boolean hasRequestBody() { + return method.equals("POST") || method.equals("PUT") || method.equals("PATCH"); + } + + /** Returns the request body or null if this request doesn't have a body. */ + public final OutputStream getRequestBody() { + if (responseSource == null) { + throw new IllegalStateException(); + } + return requestBodyOut; + } + + public final boolean hasResponse() { + return responseHeaders != null; + } + + public final RequestHeaders getRequestHeaders() { + return requestHeaders; + } + + public final ResponseHeaders getResponseHeaders() { + if (responseHeaders == null) { + throw new IllegalStateException(); + } + return responseHeaders; + } + + public final int getResponseCode() { + if (responseHeaders == null) { + throw new IllegalStateException(); + } + return responseHeaders.getHeaders().getResponseCode(); + } + + public final InputStream getResponseBody() { + if (responseHeaders == null) { + throw new IllegalStateException(); + } + return responseBodyIn; + } + + public final CacheResponse getCacheResponse() { + return cacheResponse; + } + + public final Connection getConnection() { + return connection; + } + + /** + * Returns true if {@code cacheResponse} is of the right type. This + * condition is necessary but not sufficient for the cached response to + * be used. + */ + protected boolean acceptCacheResponseType(CacheResponse cacheResponse) { + return true; + } + + private void maybeCache() throws IOException { + // Are we caching at all? + if (!policy.getUseCaches()) return; + OkResponseCache responseCache = client.getOkResponseCache(); + if (responseCache == null) return; + + HttpURLConnection connectionToCache = policy.getHttpConnectionToCache(); + + // Should we cache this response for this request? + if (!responseHeaders.isCacheable(requestHeaders)) { + responseCache.maybeRemove(connectionToCache.getRequestMethod(), uri); + return; + } + + // Offer this request to the cache. + cacheRequest = responseCache.put(uri, connectionToCache); + } + + /** + * Cause the socket connection to be released to the connection pool when + * it is no longer needed. If it is already unneeded, it will be pooled + * immediately. Otherwise the connection is held so that redirects can be + * handled by the same connection. + */ + public final void automaticallyReleaseConnectionToPool() { + automaticallyReleaseConnectionToPool = true; + if (connection != null && connectionReleased) { + client.getConnectionPool().recycle(connection); + connection = null; + } + } + + /** + * Releases this engine so that its resources may be either reused or + * closed. Also call {@link #automaticallyReleaseConnectionToPool} unless + * the connection will be used to follow a redirect. + */ + public final void release(boolean streamCanceled) { + // If the response body comes from the cache, close it. + if (responseBodyIn == cachedResponseBody) { + Util.closeQuietly(responseBodyIn); + } + + if (!connectionReleased && connection != null) { + connectionReleased = true; + + if (transport == null + || !transport.makeReusable(streamCanceled, requestBodyOut, responseTransferIn)) { + Util.closeQuietly(connection); + connection = null; + } else if (automaticallyReleaseConnectionToPool) { + client.getConnectionPool().recycle(connection); + connection = null; + } + } + } + + private void initContentStream(InputStream transferStream) throws IOException { + responseTransferIn = transferStream; + if (transparentGzip && responseHeaders.isContentEncodingGzip()) { + // If the response was transparently gzipped, remove the gzip header field + // so clients don't double decompress. http://b/3009828 + // + // Also remove the Content-Length in this case because it contains the + // length 528 of the gzipped response. This isn't terribly useful and is + // dangerous because 529 clients can query the content length, but not + // the content encoding. + responseHeaders.stripContentEncoding(); + responseHeaders.stripContentLength(); + responseBodyIn = new GZIPInputStream(transferStream); + } else { + responseBodyIn = transferStream; + } + } + + /** + * Returns true if the response must have a (possibly 0-length) body. + * See RFC 2616 section 4.3. + */ + public final boolean hasResponseBody() { + int responseCode = responseHeaders.getHeaders().getResponseCode(); + + // HEAD requests never yield a body regardless of the response headers. + if (method.equals("HEAD")) { + return false; + } + + if ((responseCode < HTTP_CONTINUE || responseCode >= 200) + && responseCode != HttpURLConnectionImpl.HTTP_NO_CONTENT + && responseCode != HttpURLConnectionImpl.HTTP_NOT_MODIFIED) { + return true; + } + + // If the Content-Length or Transfer-Encoding headers disagree with the + // response code, the response is malformed. For best compatibility, we + // honor the headers. + if (responseHeaders.getContentLength() != -1 || responseHeaders.isChunked()) { + return true; + } + + return false; + } + + /** + * Populates requestHeaders with defaults and cookies. + * + *

This client doesn't specify a default {@code Accept} header because it + * doesn't know what content types the application is interested in. + */ + private void prepareRawRequestHeaders() throws IOException { + requestHeaders.getHeaders().setRequestLine(getRequestLine()); + + if (requestHeaders.getUserAgent() == null) { + requestHeaders.setUserAgent(getDefaultUserAgent()); + } + + if (requestHeaders.getHost() == null) { + requestHeaders.setHost(getOriginAddress(policy.getURL())); + } + + if ((connection == null || connection.getHttpMinorVersion() != 0) + && requestHeaders.getConnection() == null) { + requestHeaders.setConnection("Keep-Alive"); + } + + if (requestHeaders.getAcceptEncoding() == null) { + transparentGzip = true; + requestHeaders.setAcceptEncoding("gzip"); + } + + if (hasRequestBody() && requestHeaders.getContentType() == null) { + requestHeaders.setContentType("application/x-www-form-urlencoded"); + } + + long ifModifiedSince = policy.getIfModifiedSince(); + if (ifModifiedSince != 0) { + requestHeaders.setIfModifiedSince(new Date(ifModifiedSince)); + } + + CookieHandler cookieHandler = client.getCookieHandler(); + if (cookieHandler != null) { + requestHeaders.addCookies( + cookieHandler.get(uri, requestHeaders.getHeaders().toMultimap(false))); + } + } + + /** + * Returns the request status line, like "GET / HTTP/1.1". This is exposed + * to the application by {@link HttpURLConnectionImpl#getHeaderFields}, so + * it needs to be set even if the transport is SPDY. + */ + String getRequestLine() { + String protocol = + (connection == null || connection.getHttpMinorVersion() != 0) ? "HTTP/1.1" : "HTTP/1.0"; + return method + " " + requestString() + " " + protocol; + } + + private String requestString() { + URL url = policy.getURL(); + if (includeAuthorityInRequestLine()) { + return url.toString(); + } else { + return requestPath(url); + } + } + + /** + * Returns the path to request, like the '/' in 'GET / HTTP/1.1'. Never + * empty, even if the request URL is. Includes the query component if it + * exists. + */ + public static String requestPath(URL url) { + String fileOnly = url.getFile(); + if (fileOnly == null) { + return "/"; + } else if (!fileOnly.startsWith("/")) { + return "/" + fileOnly; + } else { + return fileOnly; + } + } + + /** + * Returns true if the request line should contain the full URL with host + * and port (like "GET http://android.com/foo HTTP/1.1") or only the path + * (like "GET /foo HTTP/1.1"). + * + *

This is non-final because for HTTPS it's never necessary to supply the + * full URL, even if a proxy is in use. + */ + protected boolean includeAuthorityInRequestLine() { + return connection == null + ? policy.usingProxy() // A proxy was requested. + : connection.getRoute().getProxy().type() == Proxy.Type.HTTP; // A proxy was selected. + } + + public static String getDefaultUserAgent() { + String agent = System.getProperty("http.agent"); + return agent != null ? agent : ("Java" + System.getProperty("java.version")); + } + + public static String getOriginAddress(URL url) { + int port = url.getPort(); + String result = url.getHost(); + if (port > 0 && port != getDefaultPort(url.getProtocol())) { + result = result + ":" + port; + } + return result; + } + + /** + * Flushes the remaining request header and body, parses the HTTP response + * headers and starts reading the HTTP response body if it exists. + */ + public final void readResponse() throws IOException { + if (hasResponse()) { + responseHeaders.setResponseSource(responseSource); + return; + } + + if (responseSource == null) { + throw new IllegalStateException("readResponse() without sendRequest()"); + } + + if (!responseSource.requiresConnection()) { + return; + } + + if (sentRequestMillis == -1) { + if (requestBodyOut instanceof RetryableOutputStream) { + int contentLength = ((RetryableOutputStream) requestBodyOut).contentLength(); + requestHeaders.setContentLength(contentLength); + } + transport.writeRequestHeaders(); + } + + if (requestBodyOut != null) { + requestBodyOut.close(); + if (requestBodyOut instanceof RetryableOutputStream) { + transport.writeRequestBody((RetryableOutputStream) requestBodyOut); + } + } + + transport.flushRequest(); + + responseHeaders = transport.readResponseHeaders(); + responseHeaders.setLocalTimestamps(sentRequestMillis, System.currentTimeMillis()); + responseHeaders.setResponseSource(responseSource); + + if (responseSource == ResponseSource.CONDITIONAL_CACHE) { + if (cachedResponseHeaders.validate(responseHeaders)) { + release(false); + ResponseHeaders combinedHeaders = cachedResponseHeaders.combine(responseHeaders); + this.responseHeaders = combinedHeaders; + + // Update the cache after applying the combined headers but before initializing the content + // stream, otherwise the Content-Encoding header (if present) will be stripped from the + // combined headers and not end up in the cache file if transparent gzip compression is + // turned on. + OkResponseCache responseCache = client.getOkResponseCache(); + responseCache.trackConditionalCacheHit(); + responseCache.update(cacheResponse, policy.getHttpConnectionToCache()); + + initContentStream(cachedResponseBody); + return; + } else { + Util.closeQuietly(cachedResponseBody); + } + } + + if (hasResponseBody()) { + maybeCache(); // reentrant. this calls into user code which may call back into this! + } + + initContentStream(transport.getTransferStream(cacheRequest)); + } + + protected TunnelRequest getTunnelConfig() { + return null; + } + + public void receiveHeaders(RawHeaders headers) throws IOException { + CookieHandler cookieHandler = client.getCookieHandler(); + if (cookieHandler != null) { + cookieHandler.put(uri, headers.toMultimap(true)); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpTransport.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpTransport.java new file mode 100755 index 0000000..c967830 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpTransport.java @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.Connection; +import com.squareup.okhttp.internal.AbstractOutputStream; +import com.squareup.okhttp.internal.Util; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.CacheRequest; +import java.net.ProtocolException; +import java.net.Socket; + +import static com.squareup.okhttp.internal.Util.checkOffsetAndCount; + +public final class HttpTransport implements Transport { + /** + * The timeout to use while discarding a stream of input data. Since this is + * used for connection reuse, this timeout should be significantly less than + * the time it takes to establish a new connection. + */ + private static final int DISCARD_STREAM_TIMEOUT_MILLIS = 100; + + public static final int DEFAULT_CHUNK_LENGTH = 1024; + + private final HttpEngine httpEngine; + private final InputStream socketIn; + private final OutputStream socketOut; + + /** + * This stream buffers the request headers and the request body when their + * combined size is less than MAX_REQUEST_BUFFER_LENGTH. By combining them + * we can save socket writes, which in turn saves a packet transmission. + * This is socketOut if the request size is large or unknown. + */ + private OutputStream requestOut; + + public HttpTransport(HttpEngine httpEngine, OutputStream outputStream, InputStream inputStream) { + this.httpEngine = httpEngine; + this.socketOut = outputStream; + this.requestOut = outputStream; + this.socketIn = inputStream; + } + + @Override public OutputStream createRequestBody() throws IOException { + boolean chunked = httpEngine.requestHeaders.isChunked(); + if (!chunked + && httpEngine.policy.getChunkLength() > 0 + && httpEngine.connection.getHttpMinorVersion() != 0) { + httpEngine.requestHeaders.setChunked(); + chunked = true; + } + + // Stream a request body of unknown length. + if (chunked) { + int chunkLength = httpEngine.policy.getChunkLength(); + if (chunkLength == -1) { + chunkLength = DEFAULT_CHUNK_LENGTH; + } + writeRequestHeaders(); + return new ChunkedOutputStream(requestOut, chunkLength); + } + + // Stream a request body of a known length. + long fixedContentLength = httpEngine.policy.getFixedContentLength(); + if (fixedContentLength != -1) { + httpEngine.requestHeaders.setContentLength(fixedContentLength); + writeRequestHeaders(); + return new FixedLengthOutputStream(requestOut, fixedContentLength); + } + + long contentLength = httpEngine.requestHeaders.getContentLength(); + if (contentLength > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Use setFixedLengthStreamingMode() or " + + "setChunkedStreamingMode() for requests larger than 2 GiB."); + } + + // Buffer a request body of a known length. + if (contentLength != -1) { + writeRequestHeaders(); + return new RetryableOutputStream((int) contentLength); + } + + // Buffer a request body of an unknown length. Don't write request + // headers until the entire body is ready; otherwise we can't set the + // Content-Length header correctly. + return new RetryableOutputStream(); + } + + @Override public void flushRequest() throws IOException { + requestOut.flush(); + requestOut = socketOut; + } + + @Override public void writeRequestBody(RetryableOutputStream requestBody) throws IOException { + requestBody.writeToSocket(requestOut); + } + + /** + * Prepares the HTTP headers and sends them to the server. + * + *

For streaming requests with a body, headers must be prepared + * before the output stream has been written to. Otherwise + * the body would need to be buffered! + * + *

For non-streaming requests with a body, headers must be prepared + * after the output stream has been written to and closed. + * This ensures that the {@code Content-Length} header field receives the + * proper value. + */ + public void writeRequestHeaders() throws IOException { + httpEngine.writingRequestHeaders(); + RawHeaders headersToSend = httpEngine.requestHeaders.getHeaders(); + byte[] bytes = headersToSend.toBytes(); + requestOut.write(bytes); + } + + @Override public ResponseHeaders readResponseHeaders() throws IOException { + RawHeaders rawHeaders = RawHeaders.fromBytes(socketIn); + httpEngine.connection.setHttpMinorVersion(rawHeaders.getHttpMinorVersion()); + httpEngine.receiveHeaders(rawHeaders); + + ResponseHeaders headers = new ResponseHeaders(httpEngine.uri, rawHeaders); + headers.setTransport("http/1.1"); + return headers; + } + + public boolean makeReusable(boolean streamCanceled, OutputStream requestBodyOut, + InputStream responseBodyIn) { + if (streamCanceled) { + return false; + } + + // We cannot reuse sockets that have incomplete output. + if (requestBodyOut != null && !((AbstractOutputStream) requestBodyOut).isClosed()) { + return false; + } + + // If the request specified that the connection shouldn't be reused, don't reuse it. + if (httpEngine.requestHeaders.hasConnectionClose()) { + return false; + } + + // If the response specified that the connection shouldn't be reused, don't reuse it. + if (httpEngine.responseHeaders != null && httpEngine.responseHeaders.hasConnectionClose()) { + return false; + } + + if (responseBodyIn instanceof UnknownLengthHttpInputStream) { + return false; + } + + if (responseBodyIn != null) { + return discardStream(httpEngine, responseBodyIn); + } + + return true; + } + + /** + * Discards the response body so that the connection can be reused. This + * needs to be done judiciously, since it delays the current request in + * order to speed up a potential future request that may never occur. + * + *

A stream may be discarded to encourage response caching (a response + * cannot be cached unless it is consumed completely) or to enable connection + * reuse. + */ + private static boolean discardStream(HttpEngine httpEngine, InputStream responseBodyIn) { + Connection connection = httpEngine.connection; + if (connection == null) return false; + Socket socket = connection.getSocket(); + if (socket == null) return false; + try { + int socketTimeout = socket.getSoTimeout(); + socket.setSoTimeout(DISCARD_STREAM_TIMEOUT_MILLIS); + try { + Util.skipAll(responseBodyIn); + return true; + } finally { + socket.setSoTimeout(socketTimeout); + } + } catch (IOException e) { + return false; + } + } + + @Override public InputStream getTransferStream(CacheRequest cacheRequest) throws IOException { + if (!httpEngine.hasResponseBody()) { + return new FixedLengthInputStream(socketIn, cacheRequest, httpEngine, 0); + } + + if (httpEngine.responseHeaders.isChunked()) { + return new ChunkedInputStream(socketIn, cacheRequest, this); + } + + if (httpEngine.responseHeaders.getContentLength() != -1) { + return new FixedLengthInputStream(socketIn, cacheRequest, httpEngine, + httpEngine.responseHeaders.getContentLength()); + } + + // Wrap the input stream from the connection (rather than just returning + // "socketIn" directly here), so that we can control its use after the + // reference escapes. + return new UnknownLengthHttpInputStream(socketIn, cacheRequest, httpEngine); + } + + /** An HTTP body with a fixed length known in advance. */ + private static final class FixedLengthOutputStream extends AbstractOutputStream { + private final OutputStream socketOut; + private long bytesRemaining; + + private FixedLengthOutputStream(OutputStream socketOut, long bytesRemaining) { + this.socketOut = socketOut; + this.bytesRemaining = bytesRemaining; + } + + @Override public void write(byte[] buffer, int offset, int count) throws IOException { + checkNotClosed(); + checkOffsetAndCount(buffer.length, offset, count); + if (count > bytesRemaining) { + throw new ProtocolException("expected " + bytesRemaining + " bytes but received " + count); + } + socketOut.write(buffer, offset, count); + bytesRemaining -= count; + } + + @Override public void flush() throws IOException { + if (closed) { + return; // don't throw; this stream might have been closed on the caller's behalf + } + socketOut.flush(); + } + + @Override public void close() throws IOException { + if (closed) { + return; + } + closed = true; + if (bytesRemaining > 0) { + throw new ProtocolException("unexpected end of stream"); + } + } + } + + /** + * An HTTP body with alternating chunk sizes and chunk bodies. Chunks are + * buffered until {@code maxChunkLength} bytes are ready, at which point the + * chunk is written and the buffer is cleared. + */ + private static final class ChunkedOutputStream extends AbstractOutputStream { + private static final byte[] CRLF = { '\r', '\n' }; + private static final byte[] HEX_DIGITS = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + private static final byte[] FINAL_CHUNK = new byte[] { '0', '\r', '\n', '\r', '\n' }; + + /** Scratch space for up to 8 hex digits, and then a constant CRLF. */ + private final byte[] hex = { 0, 0, 0, 0, 0, 0, 0, 0, '\r', '\n' }; + + private final OutputStream socketOut; + private final int maxChunkLength; + private final ByteArrayOutputStream bufferedChunk; + + private ChunkedOutputStream(OutputStream socketOut, int maxChunkLength) { + this.socketOut = socketOut; + this.maxChunkLength = Math.max(1, dataLength(maxChunkLength)); + this.bufferedChunk = new ByteArrayOutputStream(maxChunkLength); + } + + /** + * Returns the amount of data that can be transmitted in a chunk whose total + * length (data+headers) is {@code dataPlusHeaderLength}. This is presumably + * useful to match sizes with wire-protocol packets. + */ + private int dataLength(int dataPlusHeaderLength) { + int headerLength = 4; // "\r\n" after the size plus another "\r\n" after the data + for (int i = dataPlusHeaderLength - headerLength; i > 0; i >>= 4) { + headerLength++; + } + return dataPlusHeaderLength - headerLength; + } + + @Override public synchronized void write(byte[] buffer, int offset, int count) + throws IOException { + checkNotClosed(); + checkOffsetAndCount(buffer.length, offset, count); + + while (count > 0) { + int numBytesWritten; + + if (bufferedChunk.size() > 0 || count < maxChunkLength) { + // fill the buffered chunk and then maybe write that to the stream + numBytesWritten = Math.min(count, maxChunkLength - bufferedChunk.size()); + // TODO: skip unnecessary copies from buffer->bufferedChunk? + bufferedChunk.write(buffer, offset, numBytesWritten); + if (bufferedChunk.size() == maxChunkLength) { + writeBufferedChunkToSocket(); + } + } else { + // write a single chunk of size maxChunkLength to the stream + numBytesWritten = maxChunkLength; + writeHex(numBytesWritten); + socketOut.write(buffer, offset, numBytesWritten); + socketOut.write(CRLF); + } + + offset += numBytesWritten; + count -= numBytesWritten; + } + } + + /** + * Equivalent to, but cheaper than writing Integer.toHexString().getBytes() + * followed by CRLF. + */ + private void writeHex(int i) throws IOException { + int cursor = 8; + do { + hex[--cursor] = HEX_DIGITS[i & 0xf]; + } while ((i >>>= 4) != 0); + socketOut.write(hex, cursor, hex.length - cursor); + } + + @Override public synchronized void flush() throws IOException { + if (closed) { + return; // don't throw; this stream might have been closed on the caller's behalf + } + writeBufferedChunkToSocket(); + socketOut.flush(); + } + + @Override public synchronized void close() throws IOException { + if (closed) { + return; + } + closed = true; + writeBufferedChunkToSocket(); + socketOut.write(FINAL_CHUNK); + } + + private void writeBufferedChunkToSocket() throws IOException { + int size = bufferedChunk.size(); + if (size <= 0) { + return; + } + + writeHex(size); + bufferedChunk.writeTo(socketOut); + bufferedChunk.reset(); + socketOut.write(CRLF); + } + } + + /** An HTTP body with a fixed length specified in advance. */ + private static class FixedLengthInputStream extends AbstractHttpInputStream { + private long bytesRemaining; + + public FixedLengthInputStream(InputStream is, CacheRequest cacheRequest, HttpEngine httpEngine, + long length) throws IOException { + super(is, httpEngine, cacheRequest); + bytesRemaining = length; + if (bytesRemaining == 0) { + endOfInput(); + } + } + + @Override public int read(byte[] buffer, int offset, int count) throws IOException { + checkOffsetAndCount(buffer.length, offset, count); + checkNotClosed(); + if (bytesRemaining == 0) { + return -1; + } + int read = in.read(buffer, offset, (int) Math.min(count, bytesRemaining)); + if (read == -1) { + unexpectedEndOfInput(); // the server didn't supply the promised content length + throw new ProtocolException("unexpected end of stream"); + } + bytesRemaining -= read; + cacheWrite(buffer, offset, read); + if (bytesRemaining == 0) { + endOfInput(); + } + return read; + } + + @Override public int available() throws IOException { + checkNotClosed(); + return bytesRemaining == 0 ? 0 : (int) Math.min(in.available(), bytesRemaining); + } + + @Override public void close() throws IOException { + if (closed) { + return; + } + if (bytesRemaining != 0 && !discardStream(httpEngine, this)) { + unexpectedEndOfInput(); + } + closed = true; + } + } + + /** An HTTP body with alternating chunk sizes and chunk bodies. */ + private static class ChunkedInputStream extends AbstractHttpInputStream { + private static final int NO_CHUNK_YET = -1; + private final HttpTransport transport; + private int bytesRemainingInChunk = NO_CHUNK_YET; + private boolean hasMoreChunks = true; + + ChunkedInputStream(InputStream is, CacheRequest cacheRequest, HttpTransport transport) + throws IOException { + super(is, transport.httpEngine, cacheRequest); + this.transport = transport; + } + + @Override public int read(byte[] buffer, int offset, int count) throws IOException { + checkOffsetAndCount(buffer.length, offset, count); + checkNotClosed(); + + if (!hasMoreChunks) { + return -1; + } + if (bytesRemainingInChunk == 0 || bytesRemainingInChunk == NO_CHUNK_YET) { + readChunkSize(); + if (!hasMoreChunks) { + return -1; + } + } + int read = in.read(buffer, offset, Math.min(count, bytesRemainingInChunk)); + if (read == -1) { + unexpectedEndOfInput(); // the server didn't supply the promised chunk length + throw new IOException("unexpected end of stream"); + } + bytesRemainingInChunk -= read; + cacheWrite(buffer, offset, read); + return read; + } + + private void readChunkSize() throws IOException { + // read the suffix of the previous chunk + if (bytesRemainingInChunk != NO_CHUNK_YET) { + Util.readAsciiLine(in); + } + String chunkSizeString = Util.readAsciiLine(in); + int index = chunkSizeString.indexOf(";"); + if (index != -1) { + chunkSizeString = chunkSizeString.substring(0, index); + } + try { + bytesRemainingInChunk = Integer.parseInt(chunkSizeString.trim(), 16); + } catch (NumberFormatException e) { + throw new ProtocolException("Expected a hex chunk size but was " + chunkSizeString); + } + if (bytesRemainingInChunk == 0) { + hasMoreChunks = false; + RawHeaders rawResponseHeaders = httpEngine.responseHeaders.getHeaders(); + RawHeaders.readHeaders(transport.socketIn, rawResponseHeaders); + httpEngine.receiveHeaders(rawResponseHeaders); + endOfInput(); + } + } + + @Override public int available() throws IOException { + checkNotClosed(); + if (!hasMoreChunks || bytesRemainingInChunk == NO_CHUNK_YET) { + return 0; + } + return Math.min(in.available(), bytesRemainingInChunk); + } + + @Override public void close() throws IOException { + if (closed) { + return; + } + if (hasMoreChunks && !discardStream(httpEngine, this)) { + unexpectedEndOfInput(); + } + closed = true; + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java new file mode 100755 index 0000000..fb4a704 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpURLConnectionImpl.java @@ -0,0 +1,590 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.Connection; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.internal.Platform; +import com.squareup.okhttp.internal.Util; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpRetryException; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.ProtocolException; +import java.net.Proxy; +import java.net.SocketPermission; +import java.net.URL; +import java.security.Permission; +import java.security.cert.CertificateException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLHandshakeException; + +import static com.squareup.okhttp.internal.Util.getEffectivePort; + +/** + * This implementation uses HttpEngine to send requests and receive responses. + * This class may use multiple HttpEngines to follow redirects, authentication + * retries, etc. to retrieve the final response body. + * + *

What does 'connected' mean?

+ * This class inherits a {@code connected} field from the superclass. That field + * is not used to indicate not whether this URLConnection is + * currently connected. Instead, it indicates whether a connection has ever been + * attempted. Once a connection has been attempted, certain properties (request + * header fields, request method, etc.) are immutable. Test the {@code + * connection} field on this class for null/non-null to determine of an instance + * is currently connected to a server. + */ +public class HttpURLConnectionImpl extends HttpURLConnection implements Policy { + + /** Numeric status code, 307: Temporary Redirect. */ + public static final int HTTP_TEMP_REDIRECT = 307; + + /** + * How many redirects should we follow? Chrome follows 21; Firefox, curl, + * and wget follow 20; Safari follows 16; and HTTP/1.0 recommends 5. + */ + private static final int MAX_REDIRECTS = 20; + + final OkHttpClient client; + + private final RawHeaders rawRequestHeaders = new RawHeaders(); + /** Like the superclass field of the same name, but a long and available on all platforms. */ + private long fixedContentLength = -1; + private int redirectionCount; + protected IOException httpEngineFailure; + protected HttpEngine httpEngine; + private Proxy selectedProxy; + + public HttpURLConnectionImpl(URL url, OkHttpClient client) { + super(url); + this.client = client; + } + + @Override public final void connect() throws IOException { + initHttpEngine(); + boolean success; + do { + success = execute(false); + } while (!success); + } + + @Override public final void disconnect() { + // Calling disconnect() before a connection exists should have no effect. + if (httpEngine != null) { + // We close the response body here instead of in + // HttpEngine.release because that is called when input + // has been completely read from the underlying socket. + // However the response body can be a GZIPInputStream that + // still has unread data. + if (httpEngine.hasResponse()) { + Util.closeQuietly(httpEngine.getResponseBody()); + } + httpEngine.release(true); + } + } + + /** + * Returns an input stream from the server in the case of error such as the + * requested file (txt, htm, html) is not found on the remote server. + */ + @Override public final InputStream getErrorStream() { + try { + HttpEngine response = getResponse(); + if (response.hasResponseBody() && response.getResponseCode() >= HTTP_BAD_REQUEST) { + return response.getResponseBody(); + } + return null; + } catch (IOException e) { + return null; + } + } + + /** + * Returns the value of the field at {@code position}. Returns null if there + * are fewer than {@code position} headers. + */ + @Override public final String getHeaderField(int position) { + try { + return getResponse().getResponseHeaders().getHeaders().getValue(position); + } catch (IOException e) { + return null; + } + } + + /** + * Returns the value of the field corresponding to the {@code fieldName}, or + * null if there is no such field. If the field has multiple values, the + * last value is returned. + */ + @Override public final String getHeaderField(String fieldName) { + try { + RawHeaders rawHeaders = getResponse().getResponseHeaders().getHeaders(); + return fieldName == null ? rawHeaders.getStatusLine() : rawHeaders.get(fieldName); + } catch (IOException e) { + return null; + } + } + + @Override public final String getHeaderFieldKey(int position) { + try { + return getResponse().getResponseHeaders().getHeaders().getFieldName(position); + } catch (IOException e) { + return null; + } + } + + @Override public final Map> getHeaderFields() { + try { + return getResponse().getResponseHeaders().getHeaders().toMultimap(true); + } catch (IOException e) { + return Collections.emptyMap(); + } + } + + @Override public final Map> getRequestProperties() { + if (connected) { + throw new IllegalStateException( + "Cannot access request header fields after connection is set"); + } + return rawRequestHeaders.toMultimap(false); + } + + @Override public final InputStream getInputStream() throws IOException { + if (!doInput) { + throw new ProtocolException("This protocol does not support input"); + } + + HttpEngine response = getResponse(); + + // if the requested file does not exist, throw an exception formerly the + // Error page from the server was returned if the requested file was + // text/html this has changed to return FileNotFoundException for all + // file types + if (getResponseCode() >= HTTP_BAD_REQUEST) { + throw new FileNotFoundException(url.toString()); + } + + InputStream result = response.getResponseBody(); + if (result == null) { + throw new ProtocolException("No response body exists; responseCode=" + getResponseCode()); + } + return result; + } + + @Override public final OutputStream getOutputStream() throws IOException { + connect(); + + OutputStream out = httpEngine.getRequestBody(); + if (out == null) { + throw new ProtocolException("method does not support a request body: " + method); + } else if (httpEngine.hasResponse()) { + throw new ProtocolException("cannot write request body after response has been read"); + } + + return out; + } + + @Override public final Permission getPermission() throws IOException { + String hostName = getURL().getHost(); + int hostPort = Util.getEffectivePort(getURL()); + if (usingProxy()) { + InetSocketAddress proxyAddress = (InetSocketAddress) client.getProxy().address(); + hostName = proxyAddress.getHostName(); + hostPort = proxyAddress.getPort(); + } + return new SocketPermission(hostName + ":" + hostPort, "connect, resolve"); + } + + @Override public final String getRequestProperty(String field) { + if (field == null) { + return null; + } + return rawRequestHeaders.get(field); + } + + @Override public void setConnectTimeout(int timeoutMillis) { + client.setConnectTimeout(timeoutMillis, TimeUnit.MILLISECONDS); + } + + @Override public int getConnectTimeout() { + return client.getConnectTimeout(); + } + + @Override public void setReadTimeout(int timeoutMillis) { + client.setReadTimeout(timeoutMillis, TimeUnit.MILLISECONDS); + } + + @Override public int getReadTimeout() { + return client.getReadTimeout(); + } + + private void initHttpEngine() throws IOException { + if (httpEngineFailure != null) { + throw httpEngineFailure; + } else if (httpEngine != null) { + return; + } + + connected = true; + try { + if (doOutput) { + if (method.equals("GET")) { + // they are requesting a stream to write to. This implies a POST method + method = "POST"; + } else if (!method.equals("POST") && !method.equals("PUT") && !method.equals("PATCH")) { + // If the request method is neither POST nor PUT nor PATCH, then you're not writing + throw new ProtocolException(method + " does not support writing"); + } + } + httpEngine = newHttpEngine(method, rawRequestHeaders, null, null); + } catch (IOException e) { + httpEngineFailure = e; + throw e; + } + } + + @Override public HttpURLConnection getHttpConnectionToCache() { + return this; + } + + private HttpEngine newHttpEngine(String method, RawHeaders requestHeaders, + Connection connection, RetryableOutputStream requestBody) throws IOException { + if (url.getProtocol().equals("http")) { + return new HttpEngine(client, this, method, requestHeaders, connection, requestBody); + } else if (url.getProtocol().equals("https")) { + return new HttpsEngine(client, this, method, requestHeaders, connection, requestBody); + } else { + throw new AssertionError(); + } + } + + /** + * Aggressively tries to get the final HTTP response, potentially making + * many HTTP requests in the process in order to cope with redirects and + * authentication. + */ + private HttpEngine getResponse() throws IOException { + initHttpEngine(); + + if (httpEngine.hasResponse()) { + return httpEngine; + } + + while (true) { + if (!execute(true)) { + continue; + } + + Retry retry = processResponseHeaders(); + if (retry == Retry.NONE) { + httpEngine.automaticallyReleaseConnectionToPool(); + return httpEngine; + } + + // The first request was insufficient. Prepare for another... + String retryMethod = method; + OutputStream requestBody = httpEngine.getRequestBody(); + + // Although RFC 2616 10.3.2 specifies that a HTTP_MOVED_PERM + // redirect should keep the same method, Chrome, Firefox and the + // RI all issue GETs when following any redirect. + int responseCode = httpEngine.getResponseCode(); + if (responseCode == HTTP_MULT_CHOICE + || responseCode == HTTP_MOVED_PERM + || responseCode == HTTP_MOVED_TEMP + || responseCode == HTTP_SEE_OTHER) { + retryMethod = "GET"; + requestBody = null; + } + + if (requestBody != null && !(requestBody instanceof RetryableOutputStream)) { + throw new HttpRetryException("Cannot retry streamed HTTP body", responseCode); + } + + if (retry == Retry.DIFFERENT_CONNECTION) { + httpEngine.automaticallyReleaseConnectionToPool(); + } + + httpEngine.release(false); + + httpEngine = newHttpEngine(retryMethod, rawRequestHeaders, httpEngine.getConnection(), + (RetryableOutputStream) requestBody); + + if (requestBody == null) { + // Drop the Content-Length header when redirected from POST to GET. + httpEngine.getRequestHeaders().removeContentLength(); + } + } + } + + /** + * Sends a request and optionally reads a response. Returns true if the + * request was successfully executed, and false if the request can be + * retried. Throws an exception if the request failed permanently. + */ + private boolean execute(boolean readResponse) throws IOException { + try { + httpEngine.sendRequest(); + if (readResponse) { + httpEngine.readResponse(); + } + + return true; + } catch (IOException e) { + if (handleFailure(e)) { + return false; + } else { + throw e; + } + } + } + + /** + * Report and attempt to recover from {@code e}. Returns true if the HTTP + * engine was replaced and the request should be retried. Otherwise the + * failure is permanent. + */ + private boolean handleFailure(IOException e) throws IOException { + RouteSelector routeSelector = httpEngine.routeSelector; + if (routeSelector != null && httpEngine.connection != null) { + routeSelector.connectFailed(httpEngine.connection, e); + } + + OutputStream requestBody = httpEngine.getRequestBody(); + boolean canRetryRequestBody = requestBody == null + || requestBody instanceof RetryableOutputStream; + if (routeSelector == null && httpEngine.connection == null // No connection. + || routeSelector != null && !routeSelector.hasNext() // No more routes to attempt. + || !isRecoverable(e) + || !canRetryRequestBody) { + httpEngineFailure = e; + return false; + } + + httpEngine.release(true); + RetryableOutputStream retryableOutputStream = (RetryableOutputStream) requestBody; + httpEngine = newHttpEngine(method, rawRequestHeaders, null, retryableOutputStream); + httpEngine.routeSelector = routeSelector; // Keep the same routeSelector. + return true; + } + + private boolean isRecoverable(IOException e) { + // If the problem was a CertificateException from the X509TrustManager, + // do not retry, we didn't have an abrupt server initiated exception. + boolean sslFailure = + e instanceof SSLHandshakeException && e.getCause() instanceof CertificateException; + boolean protocolFailure = e instanceof ProtocolException; + return !sslFailure && !protocolFailure; + } + + public HttpEngine getHttpEngine() { + return httpEngine; + } + + enum Retry { + NONE, + SAME_CONNECTION, + DIFFERENT_CONNECTION + } + + /** + * Returns the retry action to take for the current response headers. The + * headers, proxy and target URL for this connection may be adjusted to + * prepare for a follow up request. + */ + private Retry processResponseHeaders() throws IOException { + Proxy selectedProxy = httpEngine.connection != null + ? httpEngine.connection.getRoute().getProxy() + : client.getProxy(); + final int responseCode = getResponseCode(); + switch (responseCode) { + case HTTP_PROXY_AUTH: + if (selectedProxy.type() != Proxy.Type.HTTP) { + throw new ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy"); + } + // fall-through + case HTTP_UNAUTHORIZED: + boolean credentialsFound = HttpAuthenticator.processAuthHeader(client.getAuthenticator(), + getResponseCode(), httpEngine.getResponseHeaders().getHeaders(), rawRequestHeaders, + selectedProxy, url); + return credentialsFound ? Retry.SAME_CONNECTION : Retry.NONE; + + case HTTP_MULT_CHOICE: + case HTTP_MOVED_PERM: + case HTTP_MOVED_TEMP: + case HTTP_SEE_OTHER: + case HTTP_TEMP_REDIRECT: + if (!getInstanceFollowRedirects()) { + return Retry.NONE; + } + if (++redirectionCount > MAX_REDIRECTS) { + throw new ProtocolException("Too many redirects: " + redirectionCount); + } + if (responseCode == HTTP_TEMP_REDIRECT && !method.equals("GET") && !method.equals("HEAD")) { + // "If the 307 status code is received in response to a request other than GET or HEAD, + // the user agent MUST NOT automatically redirect the request" + return Retry.NONE; + } + String location = getHeaderField("Location"); + if (location == null) { + return Retry.NONE; + } + URL previousUrl = url; + url = new URL(previousUrl, location); + if (!url.getProtocol().equals("https") && !url.getProtocol().equals("http")) { + return Retry.NONE; // Don't follow redirects to unsupported protocols. + } + boolean sameProtocol = previousUrl.getProtocol().equals(url.getProtocol()); + if (!sameProtocol && !client.getFollowProtocolRedirects()) { + return Retry.NONE; // This client doesn't follow redirects across protocols. + } + boolean sameHost = previousUrl.getHost().equals(url.getHost()); + boolean samePort = getEffectivePort(previousUrl) == getEffectivePort(url); + if (sameHost && samePort && sameProtocol) { + return Retry.SAME_CONNECTION; + } else { + return Retry.DIFFERENT_CONNECTION; + } + + default: + return Retry.NONE; + } + } + + /** @see java.net.HttpURLConnection#setFixedLengthStreamingMode(int) */ + @Override public final long getFixedContentLength() { + return fixedContentLength; + } + + @Override public final int getChunkLength() { + return chunkLength; + } + + @Override public final boolean usingProxy() { + if (selectedProxy != null) { + return isValidNonDirectProxy(selectedProxy); + } + + // This behavior is a bit odd (but is probably justified by the + // oddness of the APIs involved). Before a connection is established, + // this method will return true only if this connection was explicitly + // opened with a Proxy. We don't attempt to query the ProxySelector + // at all. + return isValidNonDirectProxy(client.getProxy()); + } + + private static boolean isValidNonDirectProxy(Proxy proxy) { + return proxy != null && proxy.type() != Proxy.Type.DIRECT; + } + + @Override public String getResponseMessage() throws IOException { + return getResponse().getResponseHeaders().getHeaders().getResponseMessage(); + } + + @Override public final int getResponseCode() throws IOException { + return getResponse().getResponseCode(); + } + + @Override public final void setRequestProperty(String field, String newValue) { + if (connected) { + throw new IllegalStateException("Cannot set request property after connection is made"); + } + if (field == null) { + throw new NullPointerException("field == null"); + } + if (newValue == null) { + // Silently ignore null header values for backwards compatibility with older + // android versions as well as with other URLConnection implementations. + // + // Some implementations send a malformed HTTP header when faced with + // such requests, we respect the spec and ignore the header. + Platform.get().logW("Ignoring header " + field + " because its value was null."); + return; + } + + if ("X-Android-Transports".equals(field)) { + setTransports(newValue, false /* append */); + } else { + rawRequestHeaders.set(field, newValue); + } + } + + @Override public final void addRequestProperty(String field, String value) { + if (connected) { + throw new IllegalStateException("Cannot add request property after connection is made"); + } + if (field == null) { + throw new NullPointerException("field == null"); + } + if (value == null) { + // Silently ignore null header values for backwards compatibility with older + // android versions as well as with other URLConnection implementations. + // + // Some implementations send a malformed HTTP header when faced with + // such requests, we respect the spec and ignore the header. + Platform.get().logW("Ignoring header " + field + " because its value was null."); + return; + } + + if ("X-Android-Transports".equals(field)) { + setTransports(value, true /* append */); + } else { + rawRequestHeaders.add(field, value); + } + } + + /* + * Splits and validates a comma-separated string of transports. + * When append == false, we require that the transport list contains "http/1.1". + */ + private void setTransports(String transportsString, boolean append) { + List transportsList = new ArrayList(); + if (append) { + transportsList.addAll(client.getTransports()); + } + for (String transport : transportsString.split(",", -1)) { + transportsList.add(transport); + } + client.setTransports(transportsList); + } + + @Override public void setFixedLengthStreamingMode(int contentLength) { + setFixedLengthStreamingMode((long) contentLength); + } + + // @Override Don't override: this overload method doesn't exist prior to Java 1.7. + public void setFixedLengthStreamingMode(long contentLength) { + if (super.connected) throw new IllegalStateException("Already connected"); + if (chunkLength > 0) throw new IllegalStateException("Already in chunked mode"); + if (contentLength < 0) throw new IllegalArgumentException("contentLength < 0"); + this.fixedContentLength = contentLength; + super.fixedContentLength = (int) Math.min(contentLength, Integer.MAX_VALUE); + } + + @Override public final void setSelectedProxy(Proxy proxy) { + this.selectedProxy = proxy; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpsEngine.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpsEngine.java new file mode 100755 index 0000000..2bc1d68 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpsEngine.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.Connection; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.TunnelRequest; +import java.io.IOException; +import java.net.CacheResponse; +import java.net.SecureCacheResponse; +import java.net.URL; +import javax.net.ssl.SSLSocket; + +import static com.squareup.okhttp.internal.Util.getEffectivePort; + +public final class HttpsEngine extends HttpEngine { + /** + * Stash of HttpsEngine.connection.socket to implement requests like {@code + * HttpsURLConnection#getCipherSuite} even after the connection has been + * recycled. + */ + private SSLSocket sslSocket; + + public HttpsEngine(OkHttpClient client, Policy policy, String method, RawHeaders requestHeaders, + Connection connection, RetryableOutputStream requestBody) throws IOException { + super(client, policy, method, requestHeaders, connection, requestBody); + this.sslSocket = connection != null ? (SSLSocket) connection.getSocket() : null; + } + + @Override protected void connected(Connection connection) { + this.sslSocket = (SSLSocket) connection.getSocket(); + super.connected(connection); + } + + @Override protected boolean acceptCacheResponseType(CacheResponse cacheResponse) { + return cacheResponse instanceof SecureCacheResponse; + } + + @Override protected boolean includeAuthorityInRequestLine() { + // Even if there is a proxy, it isn't involved. Always request just the path. + return false; + } + + public SSLSocket getSslSocket() { + return sslSocket; + } + + @Override protected TunnelRequest getTunnelConfig() { + String userAgent = requestHeaders.getUserAgent(); + if (userAgent == null) { + userAgent = getDefaultUserAgent(); + } + + URL url = policy.getURL(); + return new TunnelRequest(url.getHost(), getEffectivePort(url), userAgent, + requestHeaders.getProxyAuthorization()); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java new file mode 100755 index 0000000..e64fb98 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java @@ -0,0 +1,366 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.http; + +import android.annotation.SuppressLint; +import com.squareup.okhttp.OkHttpClient; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.ProtocolException; +import java.net.SecureCacheResponse; +import java.net.URL; +import java.security.Permission; +import java.security.Principal; +import java.security.cert.Certificate; +import java.util.List; +import java.util.Map; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +public final class HttpsURLConnectionImpl extends HttpsURLConnection { + + /** HttpUrlConnectionDelegate allows reuse of HttpURLConnectionImpl. */ + private final HttpUrlConnectionDelegate delegate; + + public HttpsURLConnectionImpl(URL url, OkHttpClient client) { + super(url); + delegate = new HttpUrlConnectionDelegate(url, client); + } + + @Override public String getCipherSuite() { + SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse(); + if (cacheResponse != null) { + return cacheResponse.getCipherSuite(); + } + SSLSocket sslSocket = getSslSocket(); + if (sslSocket != null) { + return sslSocket.getSession().getCipherSuite(); + } + return null; + } + + @Override public Certificate[] getLocalCertificates() { + SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse(); + if (cacheResponse != null) { + List result = cacheResponse.getLocalCertificateChain(); + return result != null ? result.toArray(new Certificate[result.size()]) : null; + } + SSLSocket sslSocket = getSslSocket(); + if (sslSocket != null) { + return sslSocket.getSession().getLocalCertificates(); + } + return null; + } + + @Override public Certificate[] getServerCertificates() throws SSLPeerUnverifiedException { + SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse(); + if (cacheResponse != null) { + List result = cacheResponse.getServerCertificateChain(); + return result != null ? result.toArray(new Certificate[result.size()]) : null; + } + SSLSocket sslSocket = getSslSocket(); + if (sslSocket != null) { + return sslSocket.getSession().getPeerCertificates(); + } + return null; + } + + @Override public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { + SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse(); + if (cacheResponse != null) { + return cacheResponse.getPeerPrincipal(); + } + SSLSocket sslSocket = getSslSocket(); + if (sslSocket != null) { + return sslSocket.getSession().getPeerPrincipal(); + } + return null; + } + + @Override public Principal getLocalPrincipal() { + SecureCacheResponse cacheResponse = delegate.getSecureCacheResponse(); + if (cacheResponse != null) { + return cacheResponse.getLocalPrincipal(); + } + SSLSocket sslSocket = getSslSocket(); + if (sslSocket != null) { + return sslSocket.getSession().getLocalPrincipal(); + } + return null; + } + + public HttpEngine getHttpEngine() { + return delegate.getHttpEngine(); + } + + private SSLSocket getSslSocket() { + if (delegate.httpEngine == null || !delegate.httpEngine.connected) { + throw new IllegalStateException("Connection has not yet been established"); + } + return delegate.httpEngine instanceof HttpsEngine + ? ((HttpsEngine) delegate.httpEngine).getSslSocket() + : null; // Not HTTPS! Probably an https:// to http:// redirect. + } + + @Override public void disconnect() { + delegate.disconnect(); + } + + @Override public InputStream getErrorStream() { + return delegate.getErrorStream(); + } + + @Override public String getRequestMethod() { + return delegate.getRequestMethod(); + } + + @Override public int getResponseCode() throws IOException { + return delegate.getResponseCode(); + } + + @Override public String getResponseMessage() throws IOException { + return delegate.getResponseMessage(); + } + + @Override public void setRequestMethod(String method) throws ProtocolException { + delegate.setRequestMethod(method); + } + + @Override public boolean usingProxy() { + return delegate.usingProxy(); + } + + @Override public boolean getInstanceFollowRedirects() { + return delegate.getInstanceFollowRedirects(); + } + + @Override public void setInstanceFollowRedirects(boolean followRedirects) { + delegate.setInstanceFollowRedirects(followRedirects); + } + + @Override public void connect() throws IOException { + connected = true; + delegate.connect(); + } + + @Override public boolean getAllowUserInteraction() { + return delegate.getAllowUserInteraction(); + } + + @Override public Object getContent() throws IOException { + return delegate.getContent(); + } + + @SuppressWarnings("unchecked") // Spec does not generify + @Override public Object getContent(Class[] types) throws IOException { + return delegate.getContent(types); + } + + @Override public String getContentEncoding() { + return delegate.getContentEncoding(); + } + + @Override public int getContentLength() { + return delegate.getContentLength(); + } + + @Override public String getContentType() { + return delegate.getContentType(); + } + + @Override public long getDate() { + return delegate.getDate(); + } + + @Override public boolean getDefaultUseCaches() { + return delegate.getDefaultUseCaches(); + } + + @Override public boolean getDoInput() { + return delegate.getDoInput(); + } + + @Override public boolean getDoOutput() { + return delegate.getDoOutput(); + } + + @Override public long getExpiration() { + return delegate.getExpiration(); + } + + @Override public String getHeaderField(int pos) { + return delegate.getHeaderField(pos); + } + + @Override public Map> getHeaderFields() { + return delegate.getHeaderFields(); + } + + @Override public Map> getRequestProperties() { + return delegate.getRequestProperties(); + } + + @Override public void addRequestProperty(String field, String newValue) { + delegate.addRequestProperty(field, newValue); + } + + @Override public String getHeaderField(String key) { + return delegate.getHeaderField(key); + } + + @Override public long getHeaderFieldDate(String field, long defaultValue) { + return delegate.getHeaderFieldDate(field, defaultValue); + } + + @Override public int getHeaderFieldInt(String field, int defaultValue) { + return delegate.getHeaderFieldInt(field, defaultValue); + } + + @Override public String getHeaderFieldKey(int position) { + return delegate.getHeaderFieldKey(position); + } + + @Override public long getIfModifiedSince() { + return delegate.getIfModifiedSince(); + } + + @Override public InputStream getInputStream() throws IOException { + return delegate.getInputStream(); + } + + @Override public long getLastModified() { + return delegate.getLastModified(); + } + + @Override public OutputStream getOutputStream() throws IOException { + return delegate.getOutputStream(); + } + + @Override public Permission getPermission() throws IOException { + return delegate.getPermission(); + } + + @Override public String getRequestProperty(String field) { + return delegate.getRequestProperty(field); + } + + @Override public URL getURL() { + return delegate.getURL(); + } + + @Override public boolean getUseCaches() { + return delegate.getUseCaches(); + } + + @Override public void setAllowUserInteraction(boolean newValue) { + delegate.setAllowUserInteraction(newValue); + } + + @Override public void setDefaultUseCaches(boolean newValue) { + delegate.setDefaultUseCaches(newValue); + } + + @Override public void setDoInput(boolean newValue) { + delegate.setDoInput(newValue); + } + + @Override public void setDoOutput(boolean newValue) { + delegate.setDoOutput(newValue); + } + + @Override public void setIfModifiedSince(long newValue) { + delegate.setIfModifiedSince(newValue); + } + + @Override public void setRequestProperty(String field, String newValue) { + delegate.setRequestProperty(field, newValue); + } + + @Override public void setUseCaches(boolean newValue) { + delegate.setUseCaches(newValue); + } + + @Override public void setConnectTimeout(int timeoutMillis) { + delegate.setConnectTimeout(timeoutMillis); + } + + @Override public int getConnectTimeout() { + return delegate.getConnectTimeout(); + } + + @Override public void setReadTimeout(int timeoutMillis) { + delegate.setReadTimeout(timeoutMillis); + } + + @Override public int getReadTimeout() { + return delegate.getReadTimeout(); + } + + @Override public String toString() { + return delegate.toString(); + } + + @Override public void setFixedLengthStreamingMode(int contentLength) { + delegate.setFixedLengthStreamingMode(contentLength); + } + + @Override public void setChunkedStreamingMode(int chunkLength) { + delegate.setChunkedStreamingMode(chunkLength); + } + + @Override public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { + delegate.client.setHostnameVerifier(hostnameVerifier); + } + + @Override public HostnameVerifier getHostnameVerifier() { + return delegate.client.getHostnameVerifier(); + } + + @Override public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) { + delegate.client.setSslSocketFactory(sslSocketFactory); + } + + @Override public SSLSocketFactory getSSLSocketFactory() { + return delegate.client.getSslSocketFactory(); + } + + @SuppressLint("NewApi") + @Override public void setFixedLengthStreamingMode(long contentLength) { + delegate.setFixedLengthStreamingMode(contentLength); + } + + private final class HttpUrlConnectionDelegate extends HttpURLConnectionImpl { + private HttpUrlConnectionDelegate(URL url, OkHttpClient client) { + super(url, client); + } + + @Override public HttpURLConnection getHttpConnectionToCache() { + return HttpsURLConnectionImpl.this; + } + + public SecureCacheResponse getSecureCacheResponse() { + return httpEngine instanceof HttpsEngine + ? (SecureCacheResponse) httpEngine.getCacheResponse() + : null; + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/OkResponseCacheAdapter.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/OkResponseCacheAdapter.java new file mode 100755 index 0000000..5335c2b --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/OkResponseCacheAdapter.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.OkResponseCache; +import com.squareup.okhttp.ResponseSource; +import java.io.IOException; +import java.net.CacheRequest; +import java.net.CacheResponse; +import java.net.HttpURLConnection; +import java.net.ResponseCache; +import java.net.URI; +import java.net.URLConnection; +import java.util.List; +import java.util.Map; + +public final class OkResponseCacheAdapter implements OkResponseCache { + private final ResponseCache responseCache; + public OkResponseCacheAdapter(ResponseCache responseCache) { + this.responseCache = responseCache; + } + + @Override public CacheResponse get(URI uri, String requestMethod, + Map> requestHeaders) throws IOException { + return responseCache.get(uri, requestMethod, requestHeaders); + } + + @Override public CacheRequest put(URI uri, URLConnection urlConnection) throws IOException { + return responseCache.put(uri, urlConnection); + } + + @Override public void maybeRemove(String requestMethod, URI uri) throws IOException { + } + + @Override public void update(CacheResponse conditionalCacheHit, HttpURLConnection connection) + throws IOException { + } + + @Override public void trackConditionalCacheHit() { + } + + @Override public void trackResponse(ResponseSource source) { + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/Policy.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/Policy.java new file mode 100755 index 0000000..0a29d4b --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/Policy.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.http; + +import java.net.HttpURLConnection; +import java.net.Proxy; +import java.net.URL; + +public interface Policy { + /** Returns true if HTTP response caches should be used. */ + boolean getUseCaches(); + + /** Returns the HttpURLConnection instance to store in the cache. */ + HttpURLConnection getHttpConnectionToCache(); + + /** Returns the current destination URL, possibly a redirect. */ + URL getURL(); + + /** Returns the If-Modified-Since timestamp, or 0 if none is set. */ + long getIfModifiedSince(); + + /** Returns true if a non-direct proxy is specified. */ + boolean usingProxy(); + + /** @see java.net.HttpURLConnection#setChunkedStreamingMode(int) */ + int getChunkLength(); + + /** @see java.net.HttpURLConnection#setFixedLengthStreamingMode(int) */ + long getFixedContentLength(); + + /** + * Sets the current proxy that this connection is using. + * @see java.net.HttpURLConnection#usingProxy + */ + void setSelectedProxy(Proxy proxy); +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RawHeaders.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RawHeaders.java new file mode 100755 index 0000000..8b45320 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RawHeaders.java @@ -0,0 +1,447 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.internal.Util; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.ProtocolException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * The HTTP status and unparsed header fields of a single HTTP message. Values + * are represented as uninterpreted strings; use {@link RequestHeaders} and + * {@link ResponseHeaders} for interpreted headers. This class maintains the + * order of the header fields within the HTTP message. + * + *

This class tracks fields line-by-line. A field with multiple comma- + * separated values on the same line will be treated as a field with a single + * value by this class. It is the caller's responsibility to detect and split + * on commas if their field permits multiple values. This simplifies use of + * single-valued fields whose values routinely contain commas, such as cookies + * or dates. + * + *

This class trims whitespace from values. It never returns values with + * leading or trailing whitespace. + */ +public final class RawHeaders { + private static final Comparator FIELD_NAME_COMPARATOR = new Comparator() { + // @FindBugsSuppressWarnings("ES_COMPARING_PARAMETER_STRING_WITH_EQ") + @Override public int compare(String a, String b) { + if (a == b) { + return 0; + } else if (a == null) { + return -1; + } else if (b == null) { + return 1; + } else { + return String.CASE_INSENSITIVE_ORDER.compare(a, b); + } + } + }; + + private final List namesAndValues = new ArrayList(20); + private String requestLine; + private String statusLine; + private int httpMinorVersion = 1; + private int responseCode = -1; + private String responseMessage; + + public RawHeaders() { + } + + public RawHeaders(RawHeaders copyFrom) { + namesAndValues.addAll(copyFrom.namesAndValues); + requestLine = copyFrom.requestLine; + statusLine = copyFrom.statusLine; + httpMinorVersion = copyFrom.httpMinorVersion; + responseCode = copyFrom.responseCode; + responseMessage = copyFrom.responseMessage; + } + + /** Sets the request line (like "GET / HTTP/1.1"). */ + public void setRequestLine(String requestLine) { + requestLine = requestLine.trim(); + this.requestLine = requestLine; + } + + /** Sets the response status line (like "HTTP/1.0 200 OK"). */ + public void setStatusLine(String statusLine) throws IOException { + // H T T P / 1 . 1 2 0 0 T e m p o r a r y R e d i r e c t + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 + if (this.responseMessage != null) { + throw new IllegalStateException("statusLine is already set"); + } + // We allow empty message without leading white space since some servers + // do not send the white space when the message is empty. + boolean hasMessage = statusLine.length() > 13; + if (!statusLine.startsWith("HTTP/1.") + || statusLine.length() < 12 + || statusLine.charAt(8) != ' ' + || (hasMessage && statusLine.charAt(12) != ' ')) { + throw new ProtocolException("Unexpected status line: " + statusLine); + } + int httpMinorVersion = statusLine.charAt(7) - '0'; + if (httpMinorVersion < 0 || httpMinorVersion > 9) { + throw new ProtocolException("Unexpected status line: " + statusLine); + } + int responseCode; + try { + responseCode = Integer.parseInt(statusLine.substring(9, 12)); + } catch (NumberFormatException e) { + throw new ProtocolException("Unexpected status line: " + statusLine); + } + this.responseMessage = hasMessage ? statusLine.substring(13) : ""; + this.responseCode = responseCode; + this.statusLine = statusLine; + this.httpMinorVersion = httpMinorVersion; + } + + /** + * @param method like "GET", "POST", "HEAD", etc. + * @param path like "/foo/bar.html" + * @param version like "HTTP/1.1" + * @param host like "www.android.com:1234" + * @param scheme like "https" + */ + public void addSpdyRequestHeaders(String method, String path, String version, String host, + String scheme) { + // TODO: populate the statusLine for the client's benefit? + add(":method", method); + add(":scheme", scheme); + add(":path", path); + add(":version", version); + add(":host", host); + } + + public String getStatusLine() { + return statusLine; + } + + /** + * Returns the status line's HTTP minor version. This returns 0 for HTTP/1.0 + * and 1 for HTTP/1.1. This returns 1 if the HTTP version is unknown. + */ + public int getHttpMinorVersion() { + return httpMinorVersion != -1 ? httpMinorVersion : 1; + } + + /** Returns the HTTP status code or -1 if it is unknown. */ + public int getResponseCode() { + return responseCode; + } + + /** Returns the HTTP status message or null if it is unknown. */ + public String getResponseMessage() { + return responseMessage; + } + + /** + * Add an HTTP header line containing a field name, a literal colon, and a + * value. This works around empty header names and header names that start + * with a colon (created by old broken SPDY versions of the response cache). + */ + public void addLine(String line) { + int index = line.indexOf(":", 1); + if (index != -1) { + addLenient(line.substring(0, index), line.substring(index + 1)); + } else if (line.startsWith(":")) { + addLenient("", line.substring(1)); // Empty header name. + } else { + addLenient("", line); // No header name. + } + } + + /** Add a field with the specified value. */ + public void add(String fieldName, String value) { + if (fieldName == null) throw new IllegalArgumentException("fieldname == null"); + if (value == null) throw new IllegalArgumentException("value == null"); + if (fieldName.length() == 0 || fieldName.indexOf('\0') != -1 || value.indexOf('\0') != -1) { + throw new IllegalArgumentException("Unexpected header: " + fieldName + ": " + value); + } + addLenient(fieldName, value); + } + + /** + * Add a field with the specified value without any validation. Only + * appropriate for headers from the remote peer. + */ + private void addLenient(String fieldName, String value) { + namesAndValues.add(fieldName); + namesAndValues.add(value.trim()); + } + + public void removeAll(String fieldName) { + for (int i = 0; i < namesAndValues.size(); i += 2) { + if (fieldName.equalsIgnoreCase(namesAndValues.get(i))) { + namesAndValues.remove(i); // field name + namesAndValues.remove(i); // value + } + } + } + + public void addAll(String fieldName, List headerFields) { + for (String value : headerFields) { + add(fieldName, value); + } + } + + /** + * Set a field with the specified value. If the field is not found, it is + * added. If the field is found, the existing values are replaced. + */ + public void set(String fieldName, String value) { + removeAll(fieldName); + add(fieldName, value); + } + + /** Returns the number of field values. */ + public int length() { + return namesAndValues.size() / 2; + } + + /** Returns the field at {@code position} or null if that is out of range. */ + public String getFieldName(int index) { + int fieldNameIndex = index * 2; + if (fieldNameIndex < 0 || fieldNameIndex >= namesAndValues.size()) { + return null; + } + return namesAndValues.get(fieldNameIndex); + } + + /** Returns an immutable case-insensitive set of header names. */ + public Set names() { + TreeSet result = new TreeSet(String.CASE_INSENSITIVE_ORDER); + for (int i = 0; i < length(); i++) { + result.add(getFieldName(i)); + } + return Collections.unmodifiableSet(result); + } + + /** Returns the value at {@code index} or null if that is out of range. */ + public String getValue(int index) { + int valueIndex = index * 2 + 1; + if (valueIndex < 0 || valueIndex >= namesAndValues.size()) { + return null; + } + return namesAndValues.get(valueIndex); + } + + /** Returns the last value corresponding to the specified field, or null. */ + public String get(String fieldName) { + for (int i = namesAndValues.size() - 2; i >= 0; i -= 2) { + if (fieldName.equalsIgnoreCase(namesAndValues.get(i))) { + return namesAndValues.get(i + 1); + } + } + return null; + } + + /** Returns an immutable list of the header values for {@code name}. */ + public List values(String name) { + List result = null; + for (int i = 0; i < length(); i++) { + if (name.equalsIgnoreCase(getFieldName(i))) { + if (result == null) result = new ArrayList(2); + result.add(getValue(i)); + } + } + return result != null + ? Collections.unmodifiableList(result) + : Collections.emptyList(); + } + + /** @param fieldNames a case-insensitive set of HTTP header field names. */ + public RawHeaders getAll(Set fieldNames) { + RawHeaders result = new RawHeaders(); + for (int i = 0; i < namesAndValues.size(); i += 2) { + String fieldName = namesAndValues.get(i); + if (fieldNames.contains(fieldName)) { + result.add(fieldName, namesAndValues.get(i + 1)); + } + } + return result; + } + + /** Returns bytes of a request header for sending on an HTTP transport. */ + public byte[] toBytes() throws UnsupportedEncodingException { + StringBuilder result = new StringBuilder(256); + result.append(requestLine).append("\r\n"); + for (int i = 0; i < namesAndValues.size(); i += 2) { + result.append(namesAndValues.get(i)) + .append(": ") + .append(namesAndValues.get(i + 1)) + .append("\r\n"); + } + result.append("\r\n"); + return result.toString().getBytes("ISO-8859-1"); + } + + /** Parses bytes of a response header from an HTTP transport. */ + public static RawHeaders fromBytes(InputStream in) throws IOException { + RawHeaders headers; + do { + headers = new RawHeaders(); + headers.setStatusLine(Util.readAsciiLine(in)); + readHeaders(in, headers); + } while (headers.getResponseCode() == HttpEngine.HTTP_CONTINUE); + return headers; + } + + /** Reads headers or trailers into {@code out}. */ + public static void readHeaders(InputStream in, RawHeaders out) throws IOException { + // parse the result headers until the first blank line + String line; + while ((line = Util.readAsciiLine(in)).length() != 0) { + out.addLine(line); + } + } + + /** + * Returns an immutable map containing each field to its list of values. The + * status line is mapped to null. + */ + public Map> toMultimap(boolean response) { + Map> result = new TreeMap>(FIELD_NAME_COMPARATOR); + for (int i = 0; i < namesAndValues.size(); i += 2) { + String fieldName = namesAndValues.get(i); + String value = namesAndValues.get(i + 1); + + List allValues = new ArrayList(); + List otherValues = result.get(fieldName); + if (otherValues != null) { + allValues.addAll(otherValues); + } + allValues.add(value); + result.put(fieldName, Collections.unmodifiableList(allValues)); + } + if (response && statusLine != null) { + result.put(null, Collections.unmodifiableList(Collections.singletonList(statusLine))); + } else if (requestLine != null) { + result.put(null, Collections.unmodifiableList(Collections.singletonList(requestLine))); + } + return Collections.unmodifiableMap(result); + } + + /** + * Creates a new instance from the given map of fields to values. If + * present, the null field's last element will be used to set the status + * line. + */ + public static RawHeaders fromMultimap(Map> map, boolean response) + throws IOException { + if (!response) throw new UnsupportedOperationException(); + RawHeaders result = new RawHeaders(); + for (Entry> entry : map.entrySet()) { + String fieldName = entry.getKey(); + List values = entry.getValue(); + if (fieldName != null) { + for (String value : values) { + result.addLenient(fieldName, value); + } + } else if (!values.isEmpty()) { + result.setStatusLine(values.get(values.size() - 1)); + } + } + return result; + } + + /** + * Returns a list of alternating names and values. Names are all lower case. + * No names are repeated. If any name has multiple values, they are + * concatenated using "\0" as a delimiter. + */ + public List toNameValueBlock() { + Set names = new HashSet(); + List result = new ArrayList(); + for (int i = 0; i < namesAndValues.size(); i += 2) { + String name = namesAndValues.get(i).toLowerCase(Locale.US); + String value = namesAndValues.get(i + 1); + + // Drop headers that are forbidden when layering HTTP over SPDY. + if (name.equals("connection") + || name.equals("host") + || name.equals("keep-alive") + || name.equals("proxy-connection") + || name.equals("transfer-encoding")) { + continue; + } + + // If we haven't seen this name before, add the pair to the end of the list... + if (names.add(name)) { + result.add(name); + result.add(value); + continue; + } + + // ...otherwise concatenate the existing values and this value. + for (int j = 0; j < result.size(); j += 2) { + if (name.equals(result.get(j))) { + result.set(j + 1, result.get(j + 1) + "\0" + value); + break; + } + } + } + return result; + } + + /** Returns headers for a name value block containing a SPDY response. */ + public static RawHeaders fromNameValueBlock(List nameValueBlock) throws IOException { + if (nameValueBlock.size() % 2 != 0) { + throw new IllegalArgumentException("Unexpected name value block: " + nameValueBlock); + } + String status = null; + String version = null; + RawHeaders result = new RawHeaders(); + for (int i = 0; i < nameValueBlock.size(); i += 2) { + String name = nameValueBlock.get(i); + String values = nameValueBlock.get(i + 1); + for (int start = 0; start < values.length(); ) { + int end = values.indexOf('\0', start); + if (end == -1) { + end = values.length(); + } + String value = values.substring(start, end); + if (":status".equals(name)) { + status = value; + } else if (":version".equals(name)) { + version = value; + } else { + result.namesAndValues.add(name); + result.namesAndValues.add(value); + } + start = end + 1; + } + } + if (status == null) throw new ProtocolException("Expected ':status' header not present"); + if (version == null) throw new ProtocolException("Expected ':version' header not present"); + result.setStatusLine(version + " " + status); + return result; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RequestHeaders.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RequestHeaders.java new file mode 100755 index 0000000..71c3cd0 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RequestHeaders.java @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import java.net.URI; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** Parsed HTTP request headers. */ +public final class RequestHeaders { + private final URI uri; + private final RawHeaders headers; + + /** Don't use a cache to satisfy this request. */ + private boolean noCache; + private int maxAgeSeconds = -1; + private int maxStaleSeconds = -1; + private int minFreshSeconds = -1; + + /** + * This field's name "only-if-cached" is misleading. It actually means "do + * not use the network". It is set by a client who only wants to make a + * request if it can be fully satisfied by the cache. Cached responses that + * would require validation (ie. conditional gets) are not permitted if this + * header is set. + */ + private boolean onlyIfCached; + + /** + * True if the request contains an authorization field. Although this isn't + * necessarily a shared cache, it follows the spec's strict requirements for + * shared caches. + */ + private boolean hasAuthorization; + + private long contentLength = -1; + private String transferEncoding; + private String userAgent; + private String host; + private String connection; + private String acceptEncoding; + private String contentType; + private String ifModifiedSince; + private String ifNoneMatch; + private String proxyAuthorization; + + public RequestHeaders(URI uri, RawHeaders headers) { + this.uri = uri; + this.headers = headers; + + HeaderParser.CacheControlHandler handler = new HeaderParser.CacheControlHandler() { + @Override public void handle(String directive, String parameter) { + if ("no-cache".equalsIgnoreCase(directive)) { + noCache = true; + } else if ("max-age".equalsIgnoreCase(directive)) { + maxAgeSeconds = HeaderParser.parseSeconds(parameter); + } else if ("max-stale".equalsIgnoreCase(directive)) { + maxStaleSeconds = HeaderParser.parseSeconds(parameter); + } else if ("min-fresh".equalsIgnoreCase(directive)) { + minFreshSeconds = HeaderParser.parseSeconds(parameter); + } else if ("only-if-cached".equalsIgnoreCase(directive)) { + onlyIfCached = true; + } + } + }; + + for (int i = 0; i < headers.length(); i++) { + String fieldName = headers.getFieldName(i); + String value = headers.getValue(i); + if ("Cache-Control".equalsIgnoreCase(fieldName)) { + HeaderParser.parseCacheControl(value, handler); + } else if ("Pragma".equalsIgnoreCase(fieldName)) { + if ("no-cache".equalsIgnoreCase(value)) { + noCache = true; + } + } else if ("If-None-Match".equalsIgnoreCase(fieldName)) { + ifNoneMatch = value; + } else if ("If-Modified-Since".equalsIgnoreCase(fieldName)) { + ifModifiedSince = value; + } else if ("Authorization".equalsIgnoreCase(fieldName)) { + hasAuthorization = true; + } else if ("Content-Length".equalsIgnoreCase(fieldName)) { + try { + contentLength = Integer.parseInt(value); + } catch (NumberFormatException ignored) { + } + } else if ("Transfer-Encoding".equalsIgnoreCase(fieldName)) { + transferEncoding = value; + } else if ("User-Agent".equalsIgnoreCase(fieldName)) { + userAgent = value; + } else if ("Host".equalsIgnoreCase(fieldName)) { + host = value; + } else if ("Connection".equalsIgnoreCase(fieldName)) { + connection = value; + } else if ("Accept-Encoding".equalsIgnoreCase(fieldName)) { + acceptEncoding = value; + } else if ("Content-Type".equalsIgnoreCase(fieldName)) { + contentType = value; + } else if ("Proxy-Authorization".equalsIgnoreCase(fieldName)) { + proxyAuthorization = value; + } + } + } + + public boolean isChunked() { + return "chunked".equalsIgnoreCase(transferEncoding); + } + + public boolean hasConnectionClose() { + return "close".equalsIgnoreCase(connection); + } + + public URI getUri() { + return uri; + } + + public RawHeaders getHeaders() { + return headers; + } + + public boolean isNoCache() { + return noCache; + } + + public int getMaxAgeSeconds() { + return maxAgeSeconds; + } + + public int getMaxStaleSeconds() { + return maxStaleSeconds; + } + + public int getMinFreshSeconds() { + return minFreshSeconds; + } + + public boolean isOnlyIfCached() { + return onlyIfCached; + } + + public boolean hasAuthorization() { + return hasAuthorization; + } + + public long getContentLength() { + return contentLength; + } + + public String getTransferEncoding() { + return transferEncoding; + } + + public String getUserAgent() { + return userAgent; + } + + public String getHost() { + return host; + } + + public String getConnection() { + return connection; + } + + public String getAcceptEncoding() { + return acceptEncoding; + } + + public String getContentType() { + return contentType; + } + + public String getIfModifiedSince() { + return ifModifiedSince; + } + + public String getIfNoneMatch() { + return ifNoneMatch; + } + + public String getProxyAuthorization() { + return proxyAuthorization; + } + + public void setChunked() { + if (this.transferEncoding != null) { + headers.removeAll("Transfer-Encoding"); + } + headers.add("Transfer-Encoding", "chunked"); + this.transferEncoding = "chunked"; + } + + public void setContentLength(long contentLength) { + if (this.contentLength != -1) { + headers.removeAll("Content-Length"); + } + headers.add("Content-Length", Long.toString(contentLength)); + this.contentLength = contentLength; + } + + /** + * Remove the Content-Length headers. Call this when dropping the body on a + * request or response, such as when a redirect changes the method from POST + * to GET. + */ + public void removeContentLength() { + if (contentLength != -1) { + headers.removeAll("Content-Length"); + contentLength = -1; + } + } + + public void setUserAgent(String userAgent) { + if (this.userAgent != null) { + headers.removeAll("User-Agent"); + } + headers.add("User-Agent", userAgent); + this.userAgent = userAgent; + } + + public void setHost(String host) { + if (this.host != null) { + headers.removeAll("Host"); + } + headers.add("Host", host); + this.host = host; + } + + public void setConnection(String connection) { + if (this.connection != null) { + headers.removeAll("Connection"); + } + headers.add("Connection", connection); + this.connection = connection; + } + + public void setAcceptEncoding(String acceptEncoding) { + if (this.acceptEncoding != null) { + headers.removeAll("Accept-Encoding"); + } + headers.add("Accept-Encoding", acceptEncoding); + this.acceptEncoding = acceptEncoding; + } + + public void setContentType(String contentType) { + if (this.contentType != null) { + headers.removeAll("Content-Type"); + } + headers.add("Content-Type", contentType); + this.contentType = contentType; + } + + public void setIfModifiedSince(Date date) { + if (ifModifiedSince != null) { + headers.removeAll("If-Modified-Since"); + } + String formattedDate = HttpDate.format(date); + headers.add("If-Modified-Since", formattedDate); + ifModifiedSince = formattedDate; + } + + public void setIfNoneMatch(String ifNoneMatch) { + if (this.ifNoneMatch != null) { + headers.removeAll("If-None-Match"); + } + headers.add("If-None-Match", ifNoneMatch); + this.ifNoneMatch = ifNoneMatch; + } + + /** + * Returns true if the request contains conditions that save the server from + * sending a response that the client has locally. When the caller adds + * conditions, this cache won't participate in the request. + */ + public boolean hasConditions() { + return ifModifiedSince != null || ifNoneMatch != null; + } + + public void addCookies(Map> allCookieHeaders) { + for (Map.Entry> entry : allCookieHeaders.entrySet()) { + String key = entry.getKey(); + if (("Cookie".equalsIgnoreCase(key) || "Cookie2".equalsIgnoreCase(key)) + && !entry.getValue().isEmpty()) { + headers.add(key, buildCookieHeader(entry.getValue())); + } + } + } + + /** + * Send all cookies in one big header, as recommended by + * RFC 6265. + */ + private String buildCookieHeader(List cookies) { + if (cookies.size() == 1) return cookies.get(0); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < cookies.size(); i++) { + if (i > 0) sb.append("; "); + sb.append(cookies.get(i)); + } + return sb.toString(); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/ResponseHeaders.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/ResponseHeaders.java new file mode 100755 index 0000000..69e8656 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/ResponseHeaders.java @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.ResponseSource; +import com.squareup.okhttp.internal.Platform; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.TimeUnit; + +import static com.squareup.okhttp.internal.Util.equal; + +/** Parsed HTTP response headers. */ +public final class ResponseHeaders { + + /** HTTP header name for the local time when the request was sent. */ + private static final String SENT_MILLIS = Platform.get().getPrefix() + "-Sent-Millis"; + + /** HTTP header name for the local time when the response was received. */ + private static final String RECEIVED_MILLIS = Platform.get().getPrefix() + "-Received-Millis"; + + /** HTTP synthetic header with the response source. */ + static final String RESPONSE_SOURCE = Platform.get().getPrefix() + "-Response-Source"; + + /** HTTP synthetic header with the selected transport (spdy/3, http/1.1, etc). */ + static final String SELECTED_TRANSPORT = Platform.get().getPrefix() + "-Selected-Transport"; + + private final URI uri; + private final RawHeaders headers; + + /** The server's time when this response was served, if known. */ + private Date servedDate; + + /** The last modified date of the response, if known. */ + private Date lastModified; + + /** + * The expiration date of the response, if known. If both this field and the + * max age are set, the max age is preferred. + */ + private Date expires; + + /** + * Extension header set by HttpURLConnectionImpl specifying the timestamp + * when the HTTP request was first initiated. + */ + private long sentRequestMillis; + + /** + * Extension header set by HttpURLConnectionImpl specifying the timestamp + * when the HTTP response was first received. + */ + private long receivedResponseMillis; + + /** + * In the response, this field's name "no-cache" is misleading. It doesn't + * prevent us from caching the response; it only means we have to validate + * the response with the origin server before returning it. We can do this + * with a conditional get. + */ + private boolean noCache; + + /** If true, this response should not be cached. */ + private boolean noStore; + + /** + * The duration past the response's served date that it can be served + * without validation. + */ + private int maxAgeSeconds = -1; + + /** + * The "s-maxage" directive is the max age for shared caches. Not to be + * confused with "max-age" for non-shared caches, As in Firefox and Chrome, + * this directive is not honored by this cache. + */ + private int sMaxAgeSeconds = -1; + + /** + * This request header field's name "only-if-cached" is misleading. It + * actually means "do not use the network". It is set by a client who only + * wants to make a request if it can be fully satisfied by the cache. + * Cached responses that would require validation (ie. conditional gets) are + * not permitted if this header is set. + */ + private boolean isPublic; + private boolean mustRevalidate; + private String etag; + private int ageSeconds = -1; + + /** Case-insensitive set of field names. */ + private Set varyFields = Collections.emptySet(); + + private String contentEncoding; + private String transferEncoding; + private long contentLength = -1; + private String connection; + private String contentType; + + public ResponseHeaders(URI uri, RawHeaders headers) { + this.uri = uri; + this.headers = headers; + + HeaderParser.CacheControlHandler handler = new HeaderParser.CacheControlHandler() { + @Override public void handle(String directive, String parameter) { + if ("no-cache".equalsIgnoreCase(directive)) { + noCache = true; + } else if ("no-store".equalsIgnoreCase(directive)) { + noStore = true; + } else if ("max-age".equalsIgnoreCase(directive)) { + maxAgeSeconds = HeaderParser.parseSeconds(parameter); + } else if ("s-maxage".equalsIgnoreCase(directive)) { + sMaxAgeSeconds = HeaderParser.parseSeconds(parameter); + } else if ("public".equalsIgnoreCase(directive)) { + isPublic = true; + } else if ("must-revalidate".equalsIgnoreCase(directive)) { + mustRevalidate = true; + } + } + }; + + for (int i = 0; i < headers.length(); i++) { + String fieldName = headers.getFieldName(i); + String value = headers.getValue(i); + if ("Cache-Control".equalsIgnoreCase(fieldName)) { + HeaderParser.parseCacheControl(value, handler); + } else if ("Date".equalsIgnoreCase(fieldName)) { + servedDate = HttpDate.parse(value); + } else if ("Expires".equalsIgnoreCase(fieldName)) { + expires = HttpDate.parse(value); + } else if ("Last-Modified".equalsIgnoreCase(fieldName)) { + lastModified = HttpDate.parse(value); + } else if ("ETag".equalsIgnoreCase(fieldName)) { + etag = value; + } else if ("Pragma".equalsIgnoreCase(fieldName)) { + if ("no-cache".equalsIgnoreCase(value)) { + noCache = true; + } + } else if ("Age".equalsIgnoreCase(fieldName)) { + ageSeconds = HeaderParser.parseSeconds(value); + } else if ("Vary".equalsIgnoreCase(fieldName)) { + // Replace the immutable empty set with something we can mutate. + if (varyFields.isEmpty()) { + varyFields = new TreeSet(String.CASE_INSENSITIVE_ORDER); + } + for (String varyField : value.split(",")) { + varyFields.add(varyField.trim()); + } + } else if ("Content-Encoding".equalsIgnoreCase(fieldName)) { + contentEncoding = value; + } else if ("Transfer-Encoding".equalsIgnoreCase(fieldName)) { + transferEncoding = value; + } else if ("Content-Length".equalsIgnoreCase(fieldName)) { + try { + contentLength = Long.parseLong(value); + } catch (NumberFormatException ignored) { + } + } else if ("Content-Type".equalsIgnoreCase(fieldName)) { + contentType = value; + } else if ("Connection".equalsIgnoreCase(fieldName)) { + connection = value; + } else if (SENT_MILLIS.equalsIgnoreCase(fieldName)) { + sentRequestMillis = Long.parseLong(value); + } else if (RECEIVED_MILLIS.equalsIgnoreCase(fieldName)) { + receivedResponseMillis = Long.parseLong(value); + } + } + } + + public boolean isContentEncodingGzip() { + return "gzip".equalsIgnoreCase(contentEncoding); + } + + public void stripContentEncoding() { + contentEncoding = null; + headers.removeAll("Content-Encoding"); + } + + public void stripContentLength() { + contentLength = -1; + headers.removeAll("Content-Length"); + } + + public boolean isChunked() { + return "chunked".equalsIgnoreCase(transferEncoding); + } + + public boolean hasConnectionClose() { + return "close".equalsIgnoreCase(connection); + } + + public URI getUri() { + return uri; + } + + public RawHeaders getHeaders() { + return headers; + } + + public Date getServedDate() { + return servedDate; + } + + public Date getLastModified() { + return lastModified; + } + + public Date getExpires() { + return expires; + } + + public boolean isNoCache() { + return noCache; + } + + public boolean isNoStore() { + return noStore; + } + + public int getMaxAgeSeconds() { + return maxAgeSeconds; + } + + public int getSMaxAgeSeconds() { + return sMaxAgeSeconds; + } + + public boolean isPublic() { + return isPublic; + } + + public boolean isMustRevalidate() { + return mustRevalidate; + } + + public String getEtag() { + return etag; + } + + public Set getVaryFields() { + return varyFields; + } + + public String getContentEncoding() { + return contentEncoding; + } + + public long getContentLength() { + return contentLength; + } + + public String getContentType() { + return contentType; + } + + public String getConnection() { + return connection; + } + + public void setLocalTimestamps(long sentRequestMillis, long receivedResponseMillis) { + this.sentRequestMillis = sentRequestMillis; + headers.add(SENT_MILLIS, Long.toString(sentRequestMillis)); + this.receivedResponseMillis = receivedResponseMillis; + headers.add(RECEIVED_MILLIS, Long.toString(receivedResponseMillis)); + } + + public void setResponseSource(ResponseSource responseSource) { + headers.set(RESPONSE_SOURCE, responseSource.toString() + " " + headers.getResponseCode()); + } + + public void setTransport(String transport) { + headers.set(SELECTED_TRANSPORT, transport); + } + + /** + * Returns the current age of the response, in milliseconds. The calculation + * is specified by RFC 2616, 13.2.3 Age Calculations. + */ + private long computeAge(long nowMillis) { + long apparentReceivedAge = + servedDate != null ? Math.max(0, receivedResponseMillis - servedDate.getTime()) : 0; + long receivedAge = + ageSeconds != -1 ? Math.max(apparentReceivedAge, TimeUnit.SECONDS.toMillis(ageSeconds)) + : apparentReceivedAge; + long responseDuration = receivedResponseMillis - sentRequestMillis; + long residentDuration = nowMillis - receivedResponseMillis; + return receivedAge + responseDuration + residentDuration; + } + + /** + * Returns the number of milliseconds that the response was fresh for, + * starting from the served date. + */ + private long computeFreshnessLifetime() { + if (maxAgeSeconds != -1) { + return TimeUnit.SECONDS.toMillis(maxAgeSeconds); + } else if (expires != null) { + long servedMillis = servedDate != null ? servedDate.getTime() : receivedResponseMillis; + long delta = expires.getTime() - servedMillis; + return delta > 0 ? delta : 0; + } else if (lastModified != null && uri.getRawQuery() == null) { + // As recommended by the HTTP RFC and implemented in Firefox, the + // max age of a document should be defaulted to 10% of the + // document's age at the time it was served. Default expiration + // dates aren't used for URIs containing a query. + long servedMillis = servedDate != null ? servedDate.getTime() : sentRequestMillis; + long delta = servedMillis - lastModified.getTime(); + return delta > 0 ? (delta / 10) : 0; + } + return 0; + } + + /** + * Returns true if computeFreshnessLifetime used a heuristic. If we used a + * heuristic to serve a cached response older than 24 hours, we are required + * to attach a warning. + */ + private boolean isFreshnessLifetimeHeuristic() { + return maxAgeSeconds == -1 && expires == null; + } + + /** + * Returns true if this response can be stored to later serve another + * request. + */ + public boolean isCacheable(RequestHeaders request) { + // Always go to network for uncacheable response codes (RFC 2616, 13.4), + // This implementation doesn't support caching partial content. + int responseCode = headers.getResponseCode(); + if (responseCode != HttpURLConnection.HTTP_OK + && responseCode != HttpURLConnection.HTTP_NOT_AUTHORITATIVE + && responseCode != HttpURLConnection.HTTP_MULT_CHOICE + && responseCode != HttpURLConnection.HTTP_MOVED_PERM + && responseCode != HttpURLConnection.HTTP_GONE) { + return false; + } + + // Responses to authorized requests aren't cacheable unless they include + // a 'public', 'must-revalidate' or 's-maxage' directive. + if (request.hasAuthorization() && !isPublic && !mustRevalidate && sMaxAgeSeconds == -1) { + return false; + } + + if (noStore) { + return false; + } + + return true; + } + + /** + * Returns true if a Vary header contains an asterisk. Such responses cannot + * be cached. + */ + public boolean hasVaryAll() { + return varyFields.contains("*"); + } + + /** + * Returns true if none of the Vary headers on this response have changed + * between {@code cachedRequest} and {@code newRequest}. + */ + public boolean varyMatches(Map> cachedRequest, + Map> newRequest) { + for (String field : varyFields) { + if (!equal(cachedRequest.get(field), newRequest.get(field))) { + return false; + } + } + return true; + } + + /** Returns the source to satisfy {@code request} given this cached response. */ + public ResponseSource chooseResponseSource(long nowMillis, RequestHeaders request) { + // If this response shouldn't have been stored, it should never be used + // as a response source. This check should be redundant as long as the + // persistence store is well-behaved and the rules are constant. + if (!isCacheable(request)) { + return ResponseSource.NETWORK; + } + + if (request.isNoCache() || request.hasConditions()) { + return ResponseSource.NETWORK; + } + + long ageMillis = computeAge(nowMillis); + long freshMillis = computeFreshnessLifetime(); + + if (request.getMaxAgeSeconds() != -1) { + freshMillis = Math.min(freshMillis, TimeUnit.SECONDS.toMillis(request.getMaxAgeSeconds())); + } + + long minFreshMillis = 0; + if (request.getMinFreshSeconds() != -1) { + minFreshMillis = TimeUnit.SECONDS.toMillis(request.getMinFreshSeconds()); + } + + long maxStaleMillis = 0; + if (!mustRevalidate && request.getMaxStaleSeconds() != -1) { + maxStaleMillis = TimeUnit.SECONDS.toMillis(request.getMaxStaleSeconds()); + } + + if (!noCache && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) { + if (ageMillis + minFreshMillis >= freshMillis) { + headers.add("Warning", "110 HttpURLConnection \"Response is stale\""); + } + long oneDayMillis = 24 * 60 * 60 * 1000L; + if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) { + headers.add("Warning", "113 HttpURLConnection \"Heuristic expiration\""); + } + return ResponseSource.CACHE; + } + + if (lastModified != null) { + request.setIfModifiedSince(lastModified); + } else if (servedDate != null) { + request.setIfModifiedSince(servedDate); + } + + if (etag != null) { + request.setIfNoneMatch(etag); + } + + return request.hasConditions() ? ResponseSource.CONDITIONAL_CACHE : ResponseSource.NETWORK; + } + + /** + * Returns true if this cached response should be used; false if the + * network response should be used. + */ + public boolean validate(ResponseHeaders networkResponse) { + if (networkResponse.headers.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) { + return true; + } + + // The HTTP spec says that if the network's response is older than our + // cached response, we may return the cache's response. Like Chrome (but + // unlike Firefox), this client prefers to return the newer response. + if (lastModified != null + && networkResponse.lastModified != null + && networkResponse.lastModified.getTime() < lastModified.getTime()) { + return true; + } + + return false; + } + + /** + * Combines this cached header with a network header as defined by RFC 2616, + * 13.5.3. + */ + public ResponseHeaders combine(ResponseHeaders network) throws IOException { + RawHeaders result = new RawHeaders(); + result.setStatusLine(headers.getStatusLine()); + + for (int i = 0; i < headers.length(); i++) { + String fieldName = headers.getFieldName(i); + String value = headers.getValue(i); + if ("Warning".equals(fieldName) && value.startsWith("1")) { + continue; // drop 100-level freshness warnings + } + if (!isEndToEnd(fieldName) || network.headers.get(fieldName) == null) { + result.add(fieldName, value); + } + } + + for (int i = 0; i < network.headers.length(); i++) { + String fieldName = network.headers.getFieldName(i); + if (isEndToEnd(fieldName)) { + result.add(fieldName, network.headers.getValue(i)); + } + } + + return new ResponseHeaders(uri, result); + } + + /** + * Returns true if {@code fieldName} is an end-to-end HTTP header, as + * defined by RFC 2616, 13.5.1. + */ + private static boolean isEndToEnd(String fieldName) { + return !"Connection".equalsIgnoreCase(fieldName) + && !"Keep-Alive".equalsIgnoreCase(fieldName) + && !"Proxy-Authenticate".equalsIgnoreCase(fieldName) + && !"Proxy-Authorization".equalsIgnoreCase(fieldName) + && !"TE".equalsIgnoreCase(fieldName) + && !"Trailers".equalsIgnoreCase(fieldName) + && !"Transfer-Encoding".equalsIgnoreCase(fieldName) + && !"Upgrade".equalsIgnoreCase(fieldName); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RetryableOutputStream.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RetryableOutputStream.java new file mode 100755 index 0000000..5eb6b76 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RetryableOutputStream.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.internal.AbstractOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.ProtocolException; + +import static com.squareup.okhttp.internal.Util.checkOffsetAndCount; + +/** + * An HTTP request body that's completely buffered in memory. This allows + * the post body to be transparently re-sent if the HTTP request must be + * sent multiple times. + */ +final class RetryableOutputStream extends AbstractOutputStream { + private final int limit; + private final ByteArrayOutputStream content; + + public RetryableOutputStream(int limit) { + this.limit = limit; + this.content = new ByteArrayOutputStream(limit); + } + + public RetryableOutputStream() { + this.limit = -1; + this.content = new ByteArrayOutputStream(); + } + + @Override public synchronized void close() throws IOException { + if (closed) { + return; + } + closed = true; + if (content.size() < limit) { + throw new ProtocolException( + "content-length promised " + limit + " bytes, but received " + content.size()); + } + } + + @Override public synchronized void write(byte[] buffer, int offset, int count) + throws IOException { + checkNotClosed(); + checkOffsetAndCount(buffer.length, offset, count); + if (limit != -1 && content.size() > limit - count) { + throw new ProtocolException("exceeded content-length limit of " + limit + " bytes"); + } + content.write(buffer, offset, count); + } + + public synchronized int contentLength() throws IOException { + close(); + return content.size(); + } + + public void writeToSocket(OutputStream socketOut) throws IOException { + content.writeTo(socketOut); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RouteSelector.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RouteSelector.java new file mode 100755 index 0000000..1055e4f --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/RouteSelector.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2012 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.Address; +import com.squareup.okhttp.Connection; +import com.squareup.okhttp.ConnectionPool; +import com.squareup.okhttp.Route; +import com.squareup.okhttp.RouteDatabase; +import com.squareup.okhttp.internal.Dns; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.net.UnknownHostException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.NoSuchElementException; + +import static com.squareup.okhttp.internal.Util.getEffectivePort; + +/** + * Selects routes to connect to an origin server. Each connection requires a + * choice of proxy server, IP address, and TLS mode. Connections may also be + * recycled. + */ +public final class RouteSelector { + /** Uses {@link com.squareup.okhttp.internal.Platform#enableTlsExtensions}. */ + private static final int TLS_MODE_MODERN = 1; + /** Uses {@link com.squareup.okhttp.internal.Platform#supportTlsIntolerantServer}. */ + private static final int TLS_MODE_COMPATIBLE = 0; + /** No TLS mode. */ + private static final int TLS_MODE_NULL = -1; + + private final Address address; + private final URI uri; + private final ProxySelector proxySelector; + private final ConnectionPool pool; + private final Dns dns; + private final RouteDatabase routeDatabase; + + /* The most recently attempted route. */ + private Proxy lastProxy; + private InetSocketAddress lastInetSocketAddress; + + /* State for negotiating the next proxy to use. */ + private boolean hasNextProxy; + private Proxy userSpecifiedProxy; + private Iterator proxySelectorProxies; + + /* State for negotiating the next InetSocketAddress to use. */ + private InetAddress[] socketAddresses; + private int nextSocketAddressIndex; + private int socketPort; + + /* State for negotiating the next TLS configuration */ + private int nextTlsMode = TLS_MODE_NULL; + + /* State for negotiating failed routes */ + private final List postponedRoutes; + + public RouteSelector(Address address, URI uri, ProxySelector proxySelector, ConnectionPool pool, + Dns dns, RouteDatabase routeDatabase) { + this.address = address; + this.uri = uri; + this.proxySelector = proxySelector; + this.pool = pool; + this.dns = dns; + this.routeDatabase = routeDatabase; + this.postponedRoutes = new LinkedList(); + + resetNextProxy(uri, address.getProxy()); + } + + /** + * Returns true if there's another route to attempt. Every address has at + * least one route. + */ + public boolean hasNext() { + return hasNextTlsMode() || hasNextInetSocketAddress() || hasNextProxy() || hasNextPostponed(); + } + + /** + * Returns the next route address to attempt. + * + * @throws NoSuchElementException if there are no more routes to attempt. + */ + public Connection next(String method) throws IOException { + // Always prefer pooled connections over new connections. + for (Connection pooled; (pooled = pool.get(address)) != null; ) { + if (method.equals("GET") || pooled.isReadable()) return pooled; + pooled.close(); + } + + // Compute the next route to attempt. + if (!hasNextTlsMode()) { + if (!hasNextInetSocketAddress()) { + if (!hasNextProxy()) { + if (!hasNextPostponed()) { + throw new NoSuchElementException(); + } + return new Connection(nextPostponed()); + } + lastProxy = nextProxy(); + resetNextInetSocketAddress(lastProxy); + } + lastInetSocketAddress = nextInetSocketAddress(); + resetNextTlsMode(); + } + + boolean modernTls = nextTlsMode() == TLS_MODE_MODERN; + Route route = new Route(address, lastProxy, lastInetSocketAddress, modernTls); + if (routeDatabase.shouldPostpone(route)) { + postponedRoutes.add(route); + // We will only recurse in order to skip previously failed routes. They will be + // tried last. + return next(method); + } + + return new Connection(route); + } + + /** + * Clients should invoke this method when they encounter a connectivity + * failure on a connection returned by this route selector. + */ + public void connectFailed(Connection connection, IOException failure) { + Route failedRoute = connection.getRoute(); + if (failedRoute.getProxy().type() != Proxy.Type.DIRECT && proxySelector != null) { + // Tell the proxy selector when we fail to connect on a fresh connection. + proxySelector.connectFailed(uri, failedRoute.getProxy().address(), failure); + } + + routeDatabase.failed(failedRoute, failure); + } + + /** Resets {@link #nextProxy} to the first option. */ + private void resetNextProxy(URI uri, Proxy proxy) { + this.hasNextProxy = true; // This includes NO_PROXY! + if (proxy != null) { + this.userSpecifiedProxy = proxy; + } else { + List proxyList = proxySelector.select(uri); + if (proxyList != null) { + this.proxySelectorProxies = proxyList.iterator(); + } + } + } + + /** Returns true if there's another proxy to try. */ + private boolean hasNextProxy() { + return hasNextProxy; + } + + /** Returns the next proxy to try. May be PROXY.NO_PROXY but never null. */ + private Proxy nextProxy() { + // If the user specifies a proxy, try that and only that. + if (userSpecifiedProxy != null) { + hasNextProxy = false; + return userSpecifiedProxy; + } + + // Try each of the ProxySelector choices until one connection succeeds. If none succeed + // then we'll try a direct connection below. + if (proxySelectorProxies != null) { + while (proxySelectorProxies.hasNext()) { + Proxy candidate = proxySelectorProxies.next(); + if (candidate.type() != Proxy.Type.DIRECT) { + return candidate; + } + } + } + + // Finally try a direct connection. + hasNextProxy = false; + return Proxy.NO_PROXY; + } + + /** Resets {@link #nextInetSocketAddress} to the first option. */ + private void resetNextInetSocketAddress(Proxy proxy) throws UnknownHostException { + socketAddresses = null; // Clear the addresses. Necessary if getAllByName() below throws! + + String socketHost; + if (proxy.type() == Proxy.Type.DIRECT) { + socketHost = uri.getHost(); + socketPort = getEffectivePort(uri); + } else { + SocketAddress proxyAddress = proxy.address(); + if (!(proxyAddress instanceof InetSocketAddress)) { + throw new IllegalArgumentException( + "Proxy.address() is not an " + "InetSocketAddress: " + proxyAddress.getClass()); + } + InetSocketAddress proxySocketAddress = (InetSocketAddress) proxyAddress; + socketHost = proxySocketAddress.getHostName(); + socketPort = proxySocketAddress.getPort(); + } + + // Try each address for best behavior in mixed IPv4/IPv6 environments. + socketAddresses = dns.getAllByName(socketHost); + nextSocketAddressIndex = 0; + } + + /** Returns true if there's another socket address to try. */ + private boolean hasNextInetSocketAddress() { + return socketAddresses != null; + } + + /** Returns the next socket address to try. */ + private InetSocketAddress nextInetSocketAddress() throws UnknownHostException { + InetSocketAddress result = + new InetSocketAddress(socketAddresses[nextSocketAddressIndex++], socketPort); + if (nextSocketAddressIndex == socketAddresses.length) { + socketAddresses = null; // So that hasNextInetSocketAddress() returns false. + nextSocketAddressIndex = 0; + } + + return result; + } + + /** Resets {@link #nextTlsMode} to the first option. */ + private void resetNextTlsMode() { + nextTlsMode = (address.getSslSocketFactory() != null) ? TLS_MODE_MODERN : TLS_MODE_COMPATIBLE; + } + + /** Returns true if there's another TLS mode to try. */ + private boolean hasNextTlsMode() { + return nextTlsMode != TLS_MODE_NULL; + } + + /** Returns the next TLS mode to try. */ + private int nextTlsMode() { + if (nextTlsMode == TLS_MODE_MODERN) { + nextTlsMode = TLS_MODE_COMPATIBLE; + return TLS_MODE_MODERN; + } else if (nextTlsMode == TLS_MODE_COMPATIBLE) { + nextTlsMode = TLS_MODE_NULL; // So that hasNextTlsMode() returns false. + return TLS_MODE_COMPATIBLE; + } else { + throw new AssertionError(); + } + } + + /** Returns true if there is another postponed route to try. */ + private boolean hasNextPostponed() { + return !postponedRoutes.isEmpty(); + } + + /** Returns the next postponed route to try. */ + private Route nextPostponed() { + return postponedRoutes.remove(0); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/SpdyTransport.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/SpdyTransport.java new file mode 100755 index 0000000..471539a --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/SpdyTransport.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import com.squareup.okhttp.internal.spdy.ErrorCode; +import com.squareup.okhttp.internal.spdy.SpdyConnection; +import com.squareup.okhttp.internal.spdy.SpdyStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.CacheRequest; +import java.net.URL; +import java.util.List; + +public final class SpdyTransport implements Transport { + private final HttpEngine httpEngine; + private final SpdyConnection spdyConnection; + private SpdyStream stream; + + public SpdyTransport(HttpEngine httpEngine, SpdyConnection spdyConnection) { + this.httpEngine = httpEngine; + this.spdyConnection = spdyConnection; + } + + @Override public OutputStream createRequestBody() throws IOException { + long fixedContentLength = httpEngine.policy.getFixedContentLength(); + if (fixedContentLength != -1) { + httpEngine.requestHeaders.setContentLength(fixedContentLength); + } + // TODO: if we aren't streaming up to the server, we should buffer the whole request + writeRequestHeaders(); + return stream.getOutputStream(); + } + + @Override public void writeRequestHeaders() throws IOException { + if (stream != null) { + return; + } + httpEngine.writingRequestHeaders(); + RawHeaders requestHeaders = httpEngine.requestHeaders.getHeaders(); + String version = httpEngine.connection.getHttpMinorVersion() == 1 ? "HTTP/1.1" : "HTTP/1.0"; + URL url = httpEngine.policy.getURL(); + requestHeaders.addSpdyRequestHeaders(httpEngine.method, HttpEngine.requestPath(url), version, + HttpEngine.getOriginAddress(url), httpEngine.uri.getScheme()); + boolean hasRequestBody = httpEngine.hasRequestBody(); + boolean hasResponseBody = true; + stream = spdyConnection.newStream(requestHeaders.toNameValueBlock(), hasRequestBody, + hasResponseBody); + stream.setReadTimeout(httpEngine.client.getReadTimeout()); + } + + @Override public void writeRequestBody(RetryableOutputStream requestBody) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override public void flushRequest() throws IOException { + stream.getOutputStream().close(); + } + + @Override public ResponseHeaders readResponseHeaders() throws IOException { + List nameValueBlock = stream.getResponseHeaders(); + RawHeaders rawHeaders = RawHeaders.fromNameValueBlock(nameValueBlock); + httpEngine.receiveHeaders(rawHeaders); + + ResponseHeaders headers = new ResponseHeaders(httpEngine.uri, rawHeaders); + headers.setTransport("spdy/3"); + return headers; + } + + @Override public InputStream getTransferStream(CacheRequest cacheRequest) throws IOException { + return new UnknownLengthHttpInputStream(stream.getInputStream(), cacheRequest, httpEngine); + } + + @Override public boolean makeReusable(boolean streamCanceled, OutputStream requestBodyOut, + InputStream responseBodyIn) { + if (streamCanceled) { + if (stream != null) { + stream.closeLater(ErrorCode.CANCEL); + return true; + } else { + // If stream is null, it either means that writeRequestHeaders wasn't called + // or that SpdyConnection#newStream threw an IOException. In both cases there's + // nothing to do here and this stream can't be reused. + return false; + } + } + return true; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/Transport.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/Transport.java new file mode 100755 index 0000000..d408bfe --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/Transport.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.http; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.CacheRequest; + +interface Transport { + /** + * Returns an output stream where the request body can be written. The + * returned stream will of one of two types: + *

    + *
  • Direct. Bytes are written to the socket and + * forgotten. This is most efficient, particularly for large request + * bodies. The returned stream may be buffered; the caller must call + * {@link #flushRequest} before reading the response.
  • + *
  • Buffered. Bytes are written to an in memory + * buffer, and must be explicitly flushed with a call to {@link + * #writeRequestBody}. This allows HTTP authorization (401, 407) + * responses to be retransmitted transparently.
  • + *
+ */ + // TODO: don't bother retransmitting the request body? It's quite a corner + // case and there's uncertainty whether Firefox or Chrome do this + OutputStream createRequestBody() throws IOException; + + /** This should update the HTTP engine's sentRequestMillis field. */ + void writeRequestHeaders() throws IOException; + + /** + * Sends the request body returned by {@link #createRequestBody} to the + * remote peer. + */ + void writeRequestBody(RetryableOutputStream requestBody) throws IOException; + + /** Flush the request body to the underlying socket. */ + void flushRequest() throws IOException; + + /** Read response headers and update the cookie manager. */ + ResponseHeaders readResponseHeaders() throws IOException; + + // TODO: make this the content stream? + InputStream getTransferStream(CacheRequest cacheRequest) throws IOException; + + /** Returns true if the underlying connection can be recycled. */ + boolean makeReusable(boolean streamCanceled, OutputStream requestBodyOut, + InputStream responseBodyIn); +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/UnknownLengthHttpInputStream.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/UnknownLengthHttpInputStream.java new file mode 100755 index 0000000..ca6bb59 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/http/UnknownLengthHttpInputStream.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.http; + +import java.io.IOException; +import java.io.InputStream; +import java.net.CacheRequest; + +import static com.squareup.okhttp.internal.Util.checkOffsetAndCount; + +/** An HTTP message body terminated by the end of the underlying stream. */ +final class UnknownLengthHttpInputStream extends AbstractHttpInputStream { + private boolean inputExhausted; + + UnknownLengthHttpInputStream(InputStream in, CacheRequest cacheRequest, HttpEngine httpEngine) + throws IOException { + super(in, httpEngine, cacheRequest); + } + + @Override public int read(byte[] buffer, int offset, int count) throws IOException { + checkOffsetAndCount(buffer.length, offset, count); + checkNotClosed(); + if (in == null || inputExhausted) { + return -1; + } + int read = in.read(buffer, offset, count); + if (read == -1) { + inputExhausted = true; + endOfInput(); + return -1; + } + cacheWrite(buffer, offset, read); + return read; + } + + @Override public int available() throws IOException { + checkNotClosed(); + return in == null ? 0 : in.available(); + } + + @Override public void close() throws IOException { + if (closed) { + return; + } + closed = true; + if (!inputExhausted) { + unexpectedEndOfInput(); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/ErrorCode.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/ErrorCode.java new file mode 100755 index 0000000..9394b69 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/ErrorCode.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2012 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.spdy; + +public enum ErrorCode { + /** Not an error! For SPDY stream resets, prefer null over NO_ERROR. */ + NO_ERROR(0, -1, 0), + + PROTOCOL_ERROR(1, 1, 1), + + /** A subtype of PROTOCOL_ERROR used by SPDY. */ + INVALID_STREAM(1, 2, -1), + + /** A subtype of PROTOCOL_ERROR used by SPDY. */ + UNSUPPORTED_VERSION(1, 4, -1), + + /** A subtype of PROTOCOL_ERROR used by SPDY. */ + STREAM_IN_USE(1, 8, -1), + + /** A subtype of PROTOCOL_ERROR used by SPDY. */ + STREAM_ALREADY_CLOSED(1, 9, -1), + + INTERNAL_ERROR(2, 6, 2), + + FLOW_CONTROL_ERROR(3, 7, -1), + + STREAM_CLOSED(5, -1, -1), + + FRAME_TOO_LARGE(6, 11, -1), + + REFUSED_STREAM(7, 3, -1), + + CANCEL(8, 5, -1), + + COMPRESSION_ERROR(9, -1, -1), + + INVALID_CREDENTIALS(-1, 10, -1); + + public final int httpCode; + public final int spdyRstCode; + public final int spdyGoAwayCode; + + private ErrorCode(int httpCode, int spdyRstCode, int spdyGoAwayCode) { + this.httpCode = httpCode; + this.spdyRstCode = spdyRstCode; + this.spdyGoAwayCode = spdyGoAwayCode; + } + + public static ErrorCode fromSpdy3Rst(int code) { + for (ErrorCode errorCode : ErrorCode.values()) { + if (errorCode.spdyRstCode == code) return errorCode; + } + return null; + } + + public static ErrorCode fromHttp2(int code) { + for (ErrorCode errorCode : ErrorCode.values()) { + if (errorCode.httpCode == code) return errorCode; + } + return null; + } + + public static ErrorCode fromSpdyGoAway(int code) { + for (ErrorCode errorCode : ErrorCode.values()) { + if (errorCode.spdyGoAwayCode == code) return errorCode; + } + return null; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/FrameReader.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/FrameReader.java new file mode 100755 index 0000000..1371262 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/FrameReader.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.spdy; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +/** Reads transport frames for SPDY/3 or HTTP/2.0. */ +public interface FrameReader extends Closeable { + void readConnectionHeader() throws IOException; + boolean nextFrame(Handler handler) throws IOException; + + public interface Handler { + void data(boolean inFinished, int streamId, InputStream in, int length) throws IOException; + /** + * Create or update incoming headers, creating the corresponding streams + * if necessary. Frames that trigger this are SPDY SYN_STREAM, HEADERS, and + * SYN_REPLY, and HTTP/2.0 HEADERS and PUSH_PROMISE. + * + * @param inFinished true if the sender will not send further frames. + * @param outFinished true if the receiver should not send further frames. + * @param streamId the stream owning these headers. + * @param associatedStreamId the stream that triggered the sender to create + * this stream. + * @param priority or -1 for no priority. For SPDY, priorities range from 0 + * (highest) thru 7 (lowest). For HTTP/2.0, priorities range from 0 + * (highest) thru 2**31-1 (lowest). + */ + void headers(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId, + int priority, List nameValueBlock, HeadersMode headersMode); + void rstStream(int streamId, ErrorCode errorCode); + void settings(boolean clearPrevious, Settings settings); + void noop(); + void ping(boolean reply, int payload1, int payload2); + void goAway(int lastGoodStreamId, ErrorCode errorCode); + void windowUpdate(int streamId, int deltaWindowSize, boolean endFlowControl); + void priority(int streamId, int priority); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/FrameWriter.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/FrameWriter.java new file mode 100755 index 0000000..354f43d --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/FrameWriter.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.spdy; + +import java.io.Closeable; +import java.io.IOException; +import java.util.List; + +/** Writes transport frames for SPDY/3 or HTTP/2.0. */ +public interface FrameWriter extends Closeable { + /** HTTP/2.0 only. */ + void connectionHeader() throws IOException; + + /** SPDY/3 only. */ + void flush() throws IOException; + void synStream(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId, + int priority, int slot, List nameValueBlock) throws IOException; + void synReply(boolean outFinished, int streamId, List nameValueBlock) throws IOException; + void headers(int streamId, List nameValueBlock) throws IOException; + void rstStream(int streamId, ErrorCode errorCode) throws IOException; + void data(boolean outFinished, int streamId, byte[] data) throws IOException; + void data(boolean outFinished, int streamId, byte[] data, int offset, int byteCount) + throws IOException; + void settings(Settings settings) throws IOException; + void noop() throws IOException; + void ping(boolean reply, int payload1, int payload2) throws IOException; + void goAway(int lastGoodStreamId, ErrorCode errorCode) throws IOException; + void windowUpdate(int streamId, int deltaWindowSize) throws IOException; +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/HeadersMode.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/HeadersMode.java new file mode 100755 index 0000000..e16e176 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/HeadersMode.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.spdy; + +enum HeadersMode { + SPDY_SYN_STREAM, + SPDY_REPLY, + SPDY_HEADERS, + HTTP_20_HEADERS; + + /** Returns true if it is an error these headers to create a new stream. */ + public boolean failIfStreamAbsent() { + return this == SPDY_REPLY || this == SPDY_HEADERS; + } + + /** Returns true if it is an error these headers to update an existing stream. */ + public boolean failIfStreamPresent() { + return this == SPDY_SYN_STREAM; + } + + /** + * Returns true if it is an error these headers to be the initial headers of a + * response. + */ + public boolean failIfHeadersAbsent() { + return this == SPDY_HEADERS; + } + + /** + * Returns true if it is an error these headers to be update existing headers + * of a response. + */ + public boolean failIfHeadersPresent() { + return this == SPDY_REPLY; + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Hpack.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Hpack.java new file mode 100755 index 0000000..9eaeebd --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Hpack.java @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2012 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.spdy; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.List; + +/** + * Read and write HPACK v03. + * http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-03 + */ +final class Hpack { + + static class HeaderEntry { + private final String name; + private final String value; + + HeaderEntry(String name, String value) { + this.name = name; + this.value = value; + } + + // TODO: This needs to be the length in UTF-8 bytes, not the length in chars. + int length() { + return 32 + name.length() + value.length(); + } + } + + static final int PREFIX_5_BITS = 0x1f; + static final int PREFIX_6_BITS = 0x3f; + static final int PREFIX_7_BITS = 0x7f; + static final int PREFIX_8_BITS = 0xff; + + static final List INITIAL_CLIENT_TO_SERVER_HEADER_TABLE = Arrays.asList( + new HeaderEntry(":scheme", "http"), + new HeaderEntry(":scheme", "https"), + new HeaderEntry(":host", ""), + new HeaderEntry(":path", "/"), + new HeaderEntry(":method", "GET"), + new HeaderEntry("accept", ""), + new HeaderEntry("accept-charset", ""), + new HeaderEntry("accept-encoding", ""), + new HeaderEntry("accept-language", ""), + new HeaderEntry("cookie", ""), + new HeaderEntry("if-modified-since", ""), + new HeaderEntry("user-agent", ""), + new HeaderEntry("referer", ""), + new HeaderEntry("authorization", ""), + new HeaderEntry("allow", ""), + new HeaderEntry("cache-control", ""), + new HeaderEntry("connection", ""), + new HeaderEntry("content-length", ""), + new HeaderEntry("content-type", ""), + new HeaderEntry("date", ""), + new HeaderEntry("expect", ""), + new HeaderEntry("from", ""), + new HeaderEntry("if-match", ""), + new HeaderEntry("if-none-match", ""), + new HeaderEntry("if-range", ""), + new HeaderEntry("if-unmodified-since", ""), + new HeaderEntry("max-forwards", ""), + new HeaderEntry("proxy-authorization", ""), + new HeaderEntry("range", ""), + new HeaderEntry("via", "") + ); + + static final List INITIAL_SERVER_TO_CLIENT_HEADER_TABLE = Arrays.asList( + new HeaderEntry(":status", "200"), + new HeaderEntry("age", ""), + new HeaderEntry("cache-control", ""), + new HeaderEntry("content-length", ""), + new HeaderEntry("content-type", ""), + new HeaderEntry("date", ""), + new HeaderEntry("etag", ""), + new HeaderEntry("expires", ""), + new HeaderEntry("last-modified", ""), + new HeaderEntry("server", ""), + new HeaderEntry("set-cookie", ""), + new HeaderEntry("vary", ""), + new HeaderEntry("via", ""), + new HeaderEntry("access-control-allow-origin", ""), + new HeaderEntry("accept-ranges", ""), + new HeaderEntry("allow", ""), + new HeaderEntry("connection", ""), + new HeaderEntry("content-disposition", ""), + new HeaderEntry("content-encoding", ""), + new HeaderEntry("content-language", ""), + new HeaderEntry("content-location", ""), + new HeaderEntry("content-range", ""), + new HeaderEntry("link", ""), + new HeaderEntry("location", ""), + new HeaderEntry("proxy-authenticate", ""), + new HeaderEntry("refresh", ""), + new HeaderEntry("retry-after", ""), + new HeaderEntry("strict-transport-security", ""), + new HeaderEntry("transfer-encoding", ""), + new HeaderEntry("www-authenticate", "") + ); + + // Update these when initial tables change to sum of each entry length. + static final int INITIAL_CLIENT_TO_SERVER_HEADER_TABLE_LENGTH = 1262; + static final int INITIAL_SERVER_TO_CLIENT_HEADER_TABLE_LENGTH = 1304; + + private Hpack() { + } + + static class Reader { + private final long maxBufferSize = 4096; // TODO: needs to come from settings. + private final DataInputStream in; + + private final BitSet referenceSet = new BitSet(); + private final List headerTable; + private final List emittedHeaders = new ArrayList(); + private long bufferSize = 0; + private long bytesLeft = 0; + + Reader(DataInputStream in, boolean client) { + this.in = in; + if (client) { // we are reading from the server + this.headerTable = new ArrayList(INITIAL_SERVER_TO_CLIENT_HEADER_TABLE); + this.bufferSize = INITIAL_SERVER_TO_CLIENT_HEADER_TABLE_LENGTH; + } else { + this.headerTable = new ArrayList(INITIAL_CLIENT_TO_SERVER_HEADER_TABLE); + this.bufferSize = INITIAL_CLIENT_TO_SERVER_HEADER_TABLE_LENGTH; + } + } + + /** + * Read {@code byteCount} bytes of headers from the source stream into the + * set of emitted headers. + */ + public void readHeaders(int byteCount) throws IOException { + bytesLeft += byteCount; + // TODO: limit to 'byteCount' bytes? + + while (bytesLeft > 0) { + int b = readByte(); + + if ((b & 0x80) != 0) { + int index = readInt(b, PREFIX_7_BITS); + readIndexedHeader(index); + } else if (b == 0x60) { + readLiteralHeaderWithoutIndexingNewName(); + } else if ((b & 0xe0) == 0x60) { + int index = readInt(b, PREFIX_5_BITS); + readLiteralHeaderWithoutIndexingIndexedName(index - 1); + } else if (b == 0x40) { + readLiteralHeaderWithIncrementalIndexingNewName(); + } else if ((b & 0xe0) == 0x40) { + int index = readInt(b, PREFIX_5_BITS); + readLiteralHeaderWithIncrementalIndexingIndexedName(index - 1); + } else if (b == 0) { + readLiteralHeaderWithSubstitutionIndexingNewName(); + } else if ((b & 0xc0) == 0) { + int index = readInt(b, PREFIX_6_BITS); + readLiteralHeaderWithSubstitutionIndexingIndexedName(index - 1); + } else { + throw new AssertionError(); + } + } + } + + public void emitReferenceSet() { + for (int i = referenceSet.nextSetBit(0); i != -1; i = referenceSet.nextSetBit(i + 1)) { + emittedHeaders.add(getName(i)); + emittedHeaders.add(getValue(i)); + } + } + + /** + * Returns all headers emitted since they were last cleared, then clears the + * emitted headers. + */ + public List getAndReset() { + List result = new ArrayList(emittedHeaders); + emittedHeaders.clear(); + return result; + } + + private void readIndexedHeader(int index) { + if (referenceSet.get(index)) { + referenceSet.clear(index); + } else { + referenceSet.set(index); + } + } + + private void readLiteralHeaderWithoutIndexingIndexedName(int index) + throws IOException { + String name = getName(index); + String value = readString(); + emittedHeaders.add(name); + emittedHeaders.add(value); + } + + private void readLiteralHeaderWithoutIndexingNewName() + throws IOException { + String name = readString(); + String value = readString(); + emittedHeaders.add(name); + emittedHeaders.add(value); + } + + private void readLiteralHeaderWithIncrementalIndexingIndexedName(int nameIndex) + throws IOException { + String name = getName(nameIndex); + String value = readString(); + int index = headerTable.size(); // append to tail + insertIntoHeaderTable(index, new HeaderEntry(name, value)); + } + + private void readLiteralHeaderWithIncrementalIndexingNewName() throws IOException { + String name = readString(); + String value = readString(); + int index = headerTable.size(); // append to tail + insertIntoHeaderTable(index, new HeaderEntry(name, value)); + } + + private void readLiteralHeaderWithSubstitutionIndexingIndexedName(int nameIndex) + throws IOException { + int index = readInt(readByte(), PREFIX_8_BITS); + String name = getName(nameIndex); + String value = readString(); + insertIntoHeaderTable(index, new HeaderEntry(name, value)); + } + + private void readLiteralHeaderWithSubstitutionIndexingNewName() throws IOException { + String name = readString(); + int index = readInt(readByte(), PREFIX_8_BITS); + String value = readString(); + insertIntoHeaderTable(index, new HeaderEntry(name, value)); + } + + private String getName(int index) { + return headerTable.get(index).name; + } + + private String getValue(int index) { + return headerTable.get(index).value; + } + + private void insertIntoHeaderTable(int index, HeaderEntry entry) { + int delta = entry.length(); + if (index != headerTable.size()) { + delta -= headerTable.get(index).length(); + } + + // if the new or replacement header is too big, drop all entries. + if (delta > maxBufferSize) { + headerTable.clear(); + bufferSize = 0; + // emit the large header to the callback. + emittedHeaders.add(entry.name); + emittedHeaders.add(entry.value); + return; + } + + // Prune headers to the required length. + while (bufferSize + delta > maxBufferSize) { + remove(0); + index--; + } + + if (index < 0) { // we pruned it, so insert at beginning + index = 0; + headerTable.add(index, entry); + } else if (index == headerTable.size()) { // append to the end + headerTable.add(index, entry); + } else { // replace value at same position + headerTable.set(index, entry); + } + + bufferSize += delta; + referenceSet.set(index); + } + + private void remove(int index) { + bufferSize -= headerTable.remove(index).length(); + } + + private int readByte() throws IOException { + bytesLeft--; + return in.readByte() & 0xff; + } + + int readInt(int firstByte, int prefixMask) throws IOException { + int prefix = firstByte & prefixMask; + if (prefix < prefixMask) { + return prefix; // This was a single byte value. + } + + // This is a multibyte value. Read 7 bits at a time. + int result = prefixMask; + int shift = 0; + while (true) { + int b = readByte(); + if ((b & 0x80) != 0) { // Equivalent to (b >= 128) since b is in [0..255]. + result += (b & 0x7f) << shift; + shift += 7; + } else { + result += b << shift; // Last byte. + break; + } + } + return result; + } + + /** + * Reads a UTF-8 encoded string. Since ASCII is a subset of UTF-8, this method + * may be used to read strings that are known to be ASCII-only. + */ + public String readString() throws IOException { + int firstByte = readByte(); + int length = readInt(firstByte, PREFIX_8_BITS); + byte[] encoded = new byte[length]; + bytesLeft -= length; + in.readFully(encoded); + return new String(encoded, "UTF-8"); + } + } + + static class Writer { + private final OutputStream out; + + Writer(OutputStream out) { + this.out = out; + } + + public void writeHeaders(List nameValueBlock) throws IOException { + // TODO: implement a compression strategy. + for (int i = 0, size = nameValueBlock.size(); i < size; i += 2) { + out.write(0x60); // Literal Header without Indexing - New Name. + writeString(nameValueBlock.get(i)); + writeString(nameValueBlock.get(i + 1)); + } + } + + public void writeInt(int value, int prefixMask, int bits) throws IOException { + // Write the raw value for a single byte value. + if (value < prefixMask) { + out.write(bits | value); + return; + } + + // Write the mask to start a multibyte value. + out.write(bits | prefixMask); + value -= prefixMask; + + // Write 7 bits at a time 'til we're done. + while (value >= 0x80) { + int b = value & 0x7f; + out.write(b | 0x80); + value >>>= 7; + } + out.write(value); + } + + /** + * Writes a UTF-8 encoded string. Since ASCII is a subset of UTF-8, this + * method can be used to write strings that are known to be ASCII-only. + */ + public void writeString(String headerName) throws IOException { + byte[] bytes = headerName.getBytes("UTF-8"); + writeInt(bytes.length, PREFIX_8_BITS, 0); + out.write(bytes); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Http20Draft06.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Http20Draft06.java new file mode 100755 index 0000000..3d53f48 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Http20Draft06.java @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.spdy; + +import com.squareup.okhttp.internal.Util; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.List; + +/** + * Read and write http/2 v06 frames. + * http://tools.ietf.org/html/draft-ietf-httpbis-http2-06 + */ +final class Http20Draft06 implements Variant { + private static final byte[] CONNECTION_HEADER; + static { + try { + CONNECTION_HEADER = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(); + } + } + + static final int TYPE_DATA = 0x0; + static final int TYPE_HEADERS = 0x1; + static final int TYPE_PRIORITY = 0x2; + static final int TYPE_RST_STREAM = 0x3; + static final int TYPE_SETTINGS = 0x4; + static final int TYPE_PUSH_PROMISE = 0x5; + static final int TYPE_PING = 0x6; + static final int TYPE_GOAWAY = 0x7; + static final int TYPE_WINDOW_UPDATE = 0x9; + static final int TYPE_CONTINUATION = 0xa; + + static final int FLAG_END_STREAM = 0x1; + /** Used for headers, push-promise and continuation. */ + static final int FLAG_END_HEADERS = 0x4; + static final int FLAG_PRIORITY = 0x8; + static final int FLAG_PONG = 0x1; + static final int FLAG_END_FLOW_CONTROL = 0x1; + + @Override public FrameReader newReader(InputStream in, boolean client) { + return new Reader(in, client); + } + + @Override public FrameWriter newWriter(OutputStream out, boolean client) { + return new Writer(out, client); + } + + static final class Reader implements FrameReader { + private final DataInputStream in; + private final boolean client; + private final Hpack.Reader hpackReader; + + Reader(InputStream in, boolean client) { + this.in = new DataInputStream(in); + this.client = client; + this.hpackReader = new Hpack.Reader(this.in, client); + } + + @Override public void readConnectionHeader() throws IOException { + if (client) return; // Nothing to read; servers don't send connection headers! + byte[] connectionHeader = new byte[CONNECTION_HEADER.length]; + in.readFully(connectionHeader); + if (!Arrays.equals(connectionHeader, CONNECTION_HEADER)) { + throw ioException("Expected a connection header but was " + + Arrays.toString(connectionHeader)); + } + } + + @Override public boolean nextFrame(Handler handler) throws IOException { + int w1; + try { + w1 = in.readInt(); + } catch (IOException e) { + return false; // This might be a normal socket close. + } + int w2 = in.readInt(); + + int length = (w1 & 0xffff0000) >> 16; + int type = (w1 & 0xff00) >> 8; + int flags = w1 & 0xff; + // boolean r = (w2 & 0x80000000) != 0; // Reserved. + int streamId = (w2 & 0x7fffffff); + + switch (type) { + case TYPE_DATA: + readData(handler, flags, length, streamId); + return true; + + case TYPE_HEADERS: + readHeaders(handler, flags, length, streamId); + return true; + + case TYPE_PRIORITY: + readPriority(handler, flags, length, streamId); + return true; + + case TYPE_RST_STREAM: + readRstStream(handler, flags, length, streamId); + return true; + + case TYPE_SETTINGS: + readSettings(handler, flags, length, streamId); + return true; + + case TYPE_PUSH_PROMISE: + readPushPromise(handler, flags, length, streamId); + return true; + + case TYPE_PING: + readPing(handler, flags, length, streamId); + return true; + + case TYPE_GOAWAY: + readGoAway(handler, flags, length, streamId); + return true; + + case TYPE_WINDOW_UPDATE: + readWindowUpdate(handler, flags, length, streamId); + return true; + } + + throw new UnsupportedOperationException("TODO"); + } + + private void readHeaders(Handler handler, int flags, int length, int streamId) + throws IOException { + if (streamId == 0) throw ioException("TYPE_HEADERS streamId == 0"); + + boolean inFinished = (flags & FLAG_END_STREAM) != 0; + + while (true) { + hpackReader.readHeaders(length); + + if ((flags & FLAG_END_HEADERS) != 0) { + hpackReader.emitReferenceSet(); + List namesAndValues = hpackReader.getAndReset(); + int priority = -1; // TODO: priority + handler.headers(false, inFinished, streamId, -1, priority, namesAndValues, + HeadersMode.HTTP_20_HEADERS); + return; + } + + // Read another continuation frame. + int w1 = in.readInt(); + int w2 = in.readInt(); + + length = (w1 & 0xffff0000) >> 16; + int newType = (w1 & 0xff00) >> 8; + flags = w1 & 0xff; + + // TODO: remove in draft 8: CONTINUATION no longer sets END_STREAM + inFinished = (flags & FLAG_END_STREAM) != 0; + + // boolean u = (w2 & 0x80000000) != 0; // Unused. + int newStreamId = (w2 & 0x7fffffff); + + if (newType != TYPE_CONTINUATION) { + throw ioException("TYPE_CONTINUATION didn't have FLAG_END_HEADERS"); + } + if (newStreamId != streamId) throw ioException("TYPE_CONTINUATION streamId changed"); + } + } + + private void readData(Handler handler, int flags, int length, int streamId) throws IOException { + boolean inFinished = (flags & FLAG_END_STREAM) != 0; + handler.data(inFinished, streamId, in, length); + } + + private void readPriority(Handler handler, int flags, int length, int streamId) + throws IOException { + if (length != 4) throw ioException("TYPE_PRIORITY length: %d != 4", length); + if (streamId == 0) throw ioException("TYPE_PRIORITY streamId == 0"); + int w1 = in.readInt(); + // boolean r = (w1 & 0x80000000) != 0; // Reserved. + int priority = (w1 & 0x7fffffff); + handler.priority(streamId, priority); + } + + private void readRstStream(Handler handler, int flags, int length, int streamId) + throws IOException { + if (length != 4) throw ioException("TYPE_RST_STREAM length: %d != 4", length); + if (streamId == 0) throw ioException("TYPE_RST_STREAM streamId == 0"); + int errorCodeInt = in.readInt(); + ErrorCode errorCode = ErrorCode.fromHttp2(errorCodeInt); + if (errorCode == null) { + throw ioException("TYPE_RST_STREAM unexpected error code: %d", errorCodeInt); + } + handler.rstStream(streamId, errorCode); + } + + private void readSettings(Handler handler, int flags, int length, int streamId) + throws IOException { + if (length % 8 != 0) throw ioException("TYPE_SETTINGS length %% 8 != 0: %s", length); + if (streamId != 0) throw ioException("TYPE_SETTINGS streamId != 0"); + Settings settings = new Settings(); + for (int i = 0; i < length; i += 8) { + int w1 = in.readInt(); + int value = in.readInt(); + // int r = (w1 & 0xff000000) >>> 24; // Reserved. + int id = w1 & 0xffffff; + settings.set(id, 0, value); + } + handler.settings(false, settings); + } + + private void readPushPromise(Handler handler, int flags, int length, int streamId) { + // TODO: + } + + private void readPing(Handler handler, int flags, int length, int streamId) throws IOException { + if (length != 8) throw ioException("TYPE_PING length != 8: %s", length); + if (streamId != 0) throw ioException("TYPE_PING streamId != 0"); + int payload1 = in.readInt(); + int payload2 = in.readInt(); + boolean reply = (flags & FLAG_PONG) != 0; + handler.ping(reply, payload1, payload2); + } + + private void readGoAway(Handler handler, int flags, int length, int streamId) + throws IOException { + if (length < 8) throw ioException("TYPE_GOAWAY length < 8: %s", length); + int lastStreamId = in.readInt(); + int errorCodeInt = in.readInt(); + int opaqueDataLength = length - 8; + ErrorCode errorCode = ErrorCode.fromHttp2(errorCodeInt); + if (errorCode == null) { + throw ioException("TYPE_RST_STREAM unexpected error code: %d", errorCodeInt); + } + if (Util.skipByReading(in, opaqueDataLength) != opaqueDataLength) { + throw new IOException("TYPE_GOAWAY opaque data was truncated"); + } + handler.goAway(lastStreamId, errorCode); + } + + private void readWindowUpdate(Handler handler, int flags, int length, int streamId) + throws IOException { + int w1 = in.readInt(); + // boolean r = (w1 & 0x80000000) != 0; // Reserved. + int windowSizeIncrement = (w1 & 0x7fffffff); + boolean endFlowControl = (flags & FLAG_END_FLOW_CONTROL) != 0; + handler.windowUpdate(streamId, windowSizeIncrement, endFlowControl); + } + + private static IOException ioException(String message, Object... args) throws IOException { + throw new IOException(String.format(message, args)); + } + + @Override public void close() throws IOException { + in.close(); + } + } + + static final class Writer implements FrameWriter { + private final DataOutputStream out; + private final boolean client; + private final ByteArrayOutputStream hpackBuffer; + private final Hpack.Writer hpackWriter; + + Writer(OutputStream out, boolean client) { + this.out = new DataOutputStream(out); + this.client = client; + this.hpackBuffer = new ByteArrayOutputStream(); + this.hpackWriter = new Hpack.Writer(hpackBuffer); + } + + @Override public synchronized void flush() throws IOException { + out.flush(); + } + + @Override public synchronized void connectionHeader() throws IOException { + if (!client) return; // Nothing to write; servers don't send connection headers! + out.write(CONNECTION_HEADER); + } + + @Override public synchronized void synStream(boolean outFinished, boolean inFinished, + int streamId, int associatedStreamId, int priority, int slot, List nameValueBlock) + throws IOException { + if (inFinished) throw new UnsupportedOperationException(); + headers(outFinished, streamId, priority, nameValueBlock); + } + + @Override public synchronized void synReply(boolean outFinished, int streamId, + List nameValueBlock) throws IOException { + headers(outFinished, streamId, -1, nameValueBlock); + } + + @Override public synchronized void headers(int streamId, List nameValueBlock) + throws IOException { + headers(false, streamId, -1, nameValueBlock); + } + + private void headers(boolean outFinished, int streamId, int priority, + List nameValueBlock) throws IOException { + hpackBuffer.reset(); + hpackWriter.writeHeaders(nameValueBlock); + int type = TYPE_HEADERS; + // TODO: implement CONTINUATION + int length = hpackBuffer.size(); + int flags = FLAG_END_HEADERS; + if (outFinished) flags |= FLAG_END_STREAM; + if (priority != -1) flags |= FLAG_PRIORITY; + out.writeInt((length & 0xffff) << 16 | (type & 0xff) << 8 | (flags & 0xff)); + out.writeInt(streamId & 0x7fffffff); + if (priority != -1) out.writeInt(priority & 0x7fffffff); + hpackBuffer.writeTo(out); + } + + @Override public synchronized void rstStream(int streamId, ErrorCode errorCode) + throws IOException { + throw new UnsupportedOperationException("TODO"); + } + + @Override public void data(boolean outFinished, int streamId, byte[] data) throws IOException { + data(outFinished, streamId, data, 0, data.length); + } + + @Override public synchronized void data(boolean outFinished, int streamId, byte[] data, + int offset, int byteCount) throws IOException { + int type = TYPE_DATA; + int flags = 0; + if (outFinished) flags |= FLAG_END_STREAM; + out.writeInt((byteCount & 0xffff) << 16 | (type & 0xff) << 8 | (flags & 0xff)); + out.writeInt(streamId & 0x7fffffff); + out.write(data, offset, byteCount); + } + + @Override public synchronized void settings(Settings settings) throws IOException { + int type = TYPE_SETTINGS; + int length = settings.size() * 8; + int flags = 0; + int streamId = 0; + out.writeInt((length & 0xffff) << 16 | (type & 0xff) << 8 | (flags & 0xff)); + out.writeInt(streamId & 0x7fffffff); + for (int i = 0; i < Settings.COUNT; i++) { + if (!settings.isSet(i)) continue; + out.writeInt(i & 0xffffff); + out.writeInt(settings.get(i)); + } + } + + @Override public synchronized void noop() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override public synchronized void ping(boolean reply, int payload1, int payload2) + throws IOException { + // TODO + } + + @Override public synchronized void goAway(int lastGoodStreamId, ErrorCode errorCode) + throws IOException { + // TODO + } + + @Override public synchronized void windowUpdate(int streamId, int deltaWindowSize) + throws IOException { + // TODO + } + + @Override public void close() throws IOException { + out.close(); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/IncomingStreamHandler.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/IncomingStreamHandler.java new file mode 100755 index 0000000..44d4ea2 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/IncomingStreamHandler.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.spdy; + +import java.io.IOException; + +/** Listener to be notified when a connected peer creates a new stream. */ +public interface IncomingStreamHandler { + IncomingStreamHandler REFUSE_INCOMING_STREAMS = new IncomingStreamHandler() { + @Override public void receive(SpdyStream stream) throws IOException { + stream.close(ErrorCode.REFUSED_STREAM); + } + }; + + /** + * Handle a new stream from this connection's peer. Implementations should + * respond by either {@link SpdyStream#reply replying to the stream} or + * {@link SpdyStream#close closing it}. This response does not need to be + * synchronous. + */ + void receive(SpdyStream stream) throws IOException; +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/NameValueBlockReader.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/NameValueBlockReader.java new file mode 100755 index 0000000..b731a6d --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/NameValueBlockReader.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2012 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.spdy; + +import com.squareup.okhttp.internal.Util; +import java.io.Closeable; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; + +/** + * Reads a SPDY/3 Name/Value header block. This class is made complicated by the + * requirement that we're strict with which bytes we put in the compressed bytes + * buffer. We need to put all compressed bytes into that buffer -- but no other + * bytes. + */ +class NameValueBlockReader implements Closeable { + private final DataInputStream nameValueBlockIn; + private final FillableInflaterInputStream fillableInflaterInputStream; + private int compressedLimit; + + NameValueBlockReader(final InputStream in) { + // Limit the inflater input stream to only those bytes in the Name/Value block. We cut the + // inflater off at its source because we can't predict the ratio of compressed bytes to + // uncompressed bytes. + InputStream throttleStream = new InputStream() { + @Override public int read() throws IOException { + return Util.readSingleByte(this); + } + + @Override public int read(byte[] buffer, int offset, int byteCount) throws IOException { + byteCount = Math.min(byteCount, compressedLimit); + int consumed = in.read(buffer, offset, byteCount); + compressedLimit -= consumed; + return consumed; + } + + @Override public void close() throws IOException { + in.close(); + } + }; + + // Subclass inflater to install a dictionary when it's needed. + Inflater inflater = new Inflater() { + @Override public int inflate(byte[] buffer, int offset, int count) + throws DataFormatException { + int result = super.inflate(buffer, offset, count); + if (result == 0 && needsDictionary()) { + setDictionary(Spdy3.DICTIONARY); + result = super.inflate(buffer, offset, count); + } + return result; + } + }; + + fillableInflaterInputStream = new FillableInflaterInputStream(throttleStream, inflater); + nameValueBlockIn = new DataInputStream(fillableInflaterInputStream); + } + + /** Extend the inflater stream so we can eagerly fill the compressed bytes buffer if necessary. */ + static class FillableInflaterInputStream extends InflaterInputStream { + public FillableInflaterInputStream(InputStream in, Inflater inf) { + super(in, inf); + } + + @Override public void fill() throws IOException { + super.fill(); // This method is protected in the superclass. + } + } + + public List readNameValueBlock(int length) throws IOException { + this.compressedLimit += length; + try { + int numberOfPairs = nameValueBlockIn.readInt(); + if (numberOfPairs < 0) { + throw new IOException("numberOfPairs < 0: " + numberOfPairs); + } + if (numberOfPairs > 1024) { + throw new IOException("numberOfPairs > 1024: " + numberOfPairs); + } + List entries = new ArrayList(numberOfPairs * 2); + for (int i = 0; i < numberOfPairs; i++) { + String name = readString(); + String values = readString(); + if (name.length() == 0) throw new IOException("name.length == 0"); + entries.add(name); + entries.add(values); + } + + doneReading(); + + return entries; + } catch (DataFormatException e) { + throw new IOException(e.getMessage()); + } + } + + private void doneReading() throws IOException { + if (compressedLimit == 0) return; + + // Read any outstanding unread bytes. One side-effect of deflate compression is that sometimes + // there are bytes remaining in the stream after we've consumed all of the content. + fillableInflaterInputStream.fill(); + + if (compressedLimit != 0) { + throw new IOException("compressedLimit > 0: " + compressedLimit); + } + } + + private String readString() throws DataFormatException, IOException { + int length = nameValueBlockIn.readInt(); + byte[] bytes = new byte[length]; + Util.readFully(nameValueBlockIn, bytes); + return new String(bytes, 0, length, "UTF-8"); + } + + @Override public void close() throws IOException { + nameValueBlockIn.close(); + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Ping.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Ping.java new file mode 100755 index 0000000..c585255 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Ping.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.spdy; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * A locally-originated ping. + */ +public final class Ping { + private final CountDownLatch latch = new CountDownLatch(1); + private long sent = -1; + private long received = -1; + + Ping() { + } + + void send() { + if (sent != -1) throw new IllegalStateException(); + sent = System.nanoTime(); + } + + void receive() { + if (received != -1 || sent == -1) throw new IllegalStateException(); + received = System.nanoTime(); + latch.countDown(); + } + + void cancel() { + if (received != -1 || sent == -1) throw new IllegalStateException(); + received = sent - 1; + latch.countDown(); + } + + /** + * Returns the round trip time for this ping in nanoseconds, waiting for the + * response to arrive if necessary. Returns -1 if the response was + * cancelled. + */ + public long roundTripTime() throws InterruptedException { + latch.await(); + return received - sent; + } + + /** + * Returns the round trip time for this ping in nanoseconds, or -1 if the + * response was cancelled, or -2 if the timeout elapsed before the round + * trip completed. + */ + public long roundTripTime(long timeout, TimeUnit unit) throws InterruptedException { + if (latch.await(timeout, unit)) { + return received - sent; + } else { + return -2; + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Settings.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Settings.java new file mode 100755 index 0000000..05380e2 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Settings.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2012 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.spdy; + +final class Settings { + /** + * From the spdy/3 spec, the default initial window size for all streams is + * 64 KiB. (Chrome 25 uses 10 MiB). + */ + static final int DEFAULT_INITIAL_WINDOW_SIZE = 64 * 1024; + + /** Peer request to clear durable settings. */ + static final int FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS = 0x1; + + /** Sent by servers only. The peer requests this setting persisted for future connections. */ + static final int PERSIST_VALUE = 0x1; + /** Sent by clients only. The client is reminding the server of a persisted value. */ + static final int PERSISTED = 0x2; + + /** Sender's estimate of max incoming kbps. */ + static final int UPLOAD_BANDWIDTH = 1; + /** Sender's estimate of max outgoing kbps. */ + static final int DOWNLOAD_BANDWIDTH = 2; + /** Sender's estimate of milliseconds between sending a request and receiving a response. */ + static final int ROUND_TRIP_TIME = 3; + /** Sender's maximum number of concurrent streams. */ + static final int MAX_CONCURRENT_STREAMS = 4; + /** Current CWND in Packets. */ + static final int CURRENT_CWND = 5; + /** Retransmission rate. Percentage */ + static final int DOWNLOAD_RETRANS_RATE = 6; + /** Window size in bytes. */ + static final int INITIAL_WINDOW_SIZE = 7; + /** Window size in bytes. */ + static final int CLIENT_CERTIFICATE_VECTOR_SIZE = 8; + /** Flow control options. */ + static final int FLOW_CONTROL_OPTIONS = 9; + + /** Total number of settings. */ + static final int COUNT = 10; + + /** If set, flow control is disabled for streams directed to the sender of these settings. */ + static final int FLOW_CONTROL_OPTIONS_DISABLED = 0x1; + + /** Bitfield of which flags that values. */ + private int set; + + /** Bitfield of flags that have {@link #PERSIST_VALUE}. */ + private int persistValue; + + /** Bitfield of flags that have {@link #PERSISTED}. */ + private int persisted; + + /** Flag values. */ + private final int[] values = new int[COUNT]; + + void set(int id, int idFlags, int value) { + if (id >= values.length) { + return; // Discard unknown settings. + } + + int bit = 1 << id; + set |= bit; + if ((idFlags & PERSIST_VALUE) != 0) { + persistValue |= bit; + } else { + persistValue &= ~bit; + } + if ((idFlags & PERSISTED) != 0) { + persisted |= bit; + } else { + persisted &= ~bit; + } + + values[id] = value; + } + + /** Returns true if a value has been assigned for the setting {@code id}. */ + boolean isSet(int id) { + int bit = 1 << id; + return (set & bit) != 0; + } + + /** Returns the value for the setting {@code id}, or 0 if unset. */ + int get(int id) { + return values[id]; + } + + /** Returns the flags for the setting {@code id}, or 0 if unset. */ + int flags(int id) { + int result = 0; + if (isPersisted(id)) result |= Settings.PERSISTED; + if (persistValue(id)) result |= Settings.PERSIST_VALUE; + return result; + } + + /** Returns the number of settings that have values assigned. */ + int size() { + return Integer.bitCount(set); + } + + int getUploadBandwidth(int defaultValue) { + int bit = 1 << UPLOAD_BANDWIDTH; + return (bit & set) != 0 ? values[UPLOAD_BANDWIDTH] : defaultValue; + } + + int getDownloadBandwidth(int defaultValue) { + int bit = 1 << DOWNLOAD_BANDWIDTH; + return (bit & set) != 0 ? values[DOWNLOAD_BANDWIDTH] : defaultValue; + } + + int getRoundTripTime(int defaultValue) { + int bit = 1 << ROUND_TRIP_TIME; + return (bit & set) != 0 ? values[ROUND_TRIP_TIME] : defaultValue; + } + + int getMaxConcurrentStreams(int defaultValue) { + int bit = 1 << MAX_CONCURRENT_STREAMS; + return (bit & set) != 0 ? values[MAX_CONCURRENT_STREAMS] : defaultValue; + } + + int getCurrentCwnd(int defaultValue) { + int bit = 1 << CURRENT_CWND; + return (bit & set) != 0 ? values[CURRENT_CWND] : defaultValue; + } + + int getDownloadRetransRate(int defaultValue) { + int bit = 1 << DOWNLOAD_RETRANS_RATE; + return (bit & set) != 0 ? values[DOWNLOAD_RETRANS_RATE] : defaultValue; + } + + int getInitialWindowSize(int defaultValue) { + int bit = 1 << INITIAL_WINDOW_SIZE; + return (bit & set) != 0 ? values[INITIAL_WINDOW_SIZE] : defaultValue; + } + + int getClientCertificateVectorSize(int defaultValue) { + int bit = 1 << CLIENT_CERTIFICATE_VECTOR_SIZE; + return (bit & set) != 0 ? values[CLIENT_CERTIFICATE_VECTOR_SIZE] : defaultValue; + } + + // TODO: honor this setting. + boolean isFlowControlDisabled() { + int bit = 1 << FLOW_CONTROL_OPTIONS; + int value = (bit & set) != 0 ? values[FLOW_CONTROL_OPTIONS] : 0; + return (value & FLOW_CONTROL_OPTIONS_DISABLED) != 0; + } + + /** + * Returns true if this user agent should use this setting in future SPDY + * connections to the same host. + */ + boolean persistValue(int id) { + int bit = 1 << id; + return (persistValue & bit) != 0; + } + + /** Returns true if this setting was persisted. */ + boolean isPersisted(int id) { + int bit = 1 << id; + return (persisted & bit) != 0; + } + + /** + * Writes {@code other} into this. If any setting is populated by this and + * {@code other}, the value and flags from {@code other} will be kept. + */ + void merge(Settings other) { + for (int i = 0; i < COUNT; i++) { + if (!other.isSet(i)) continue; + set(i, other.flags(i), other.get(i)); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Spdy3.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Spdy3.java new file mode 100755 index 0000000..5d9a49b --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Spdy3.java @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.spdy; + +import com.squareup.okhttp.internal.Platform; +import com.squareup.okhttp.internal.Util; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.ProtocolException; +import java.util.List; +import java.util.zip.Deflater; + +final class Spdy3 implements Variant { + static final int TYPE_DATA = 0x0; + static final int TYPE_SYN_STREAM = 0x1; + static final int TYPE_SYN_REPLY = 0x2; + static final int TYPE_RST_STREAM = 0x3; + static final int TYPE_SETTINGS = 0x4; + static final int TYPE_NOOP = 0x5; + static final int TYPE_PING = 0x6; + static final int TYPE_GOAWAY = 0x7; + static final int TYPE_HEADERS = 0x8; + static final int TYPE_WINDOW_UPDATE = 0x9; + static final int TYPE_CREDENTIAL = 0x10; + + static final int FLAG_FIN = 0x1; + static final int FLAG_UNIDIRECTIONAL = 0x2; + + static final int VERSION = 3; + + static final byte[] DICTIONARY; + static { + try { + DICTIONARY = ("\u0000\u0000\u0000\u0007options\u0000\u0000\u0000\u0004hea" + + "d\u0000\u0000\u0000\u0004post\u0000\u0000\u0000\u0003put\u0000\u0000\u0000\u0006dele" + + "te\u0000\u0000\u0000\u0005trace\u0000\u0000\u0000\u0006accept\u0000\u0000\u0000" + + "\u000Eaccept-charset\u0000\u0000\u0000\u000Faccept-encoding\u0000\u0000\u0000\u000Fa" + + "ccept-language\u0000\u0000\u0000\raccept-ranges\u0000\u0000\u0000\u0003age\u0000" + + "\u0000\u0000\u0005allow\u0000\u0000\u0000\rauthorization\u0000\u0000\u0000\rcache-co" + + "ntrol\u0000\u0000\u0000\nconnection\u0000\u0000\u0000\fcontent-base\u0000\u0000" + + "\u0000\u0010content-encoding\u0000\u0000\u0000\u0010content-language\u0000\u0000" + + "\u0000\u000Econtent-length\u0000\u0000\u0000\u0010content-location\u0000\u0000\u0000" + + "\u000Bcontent-md5\u0000\u0000\u0000\rcontent-range\u0000\u0000\u0000\fcontent-type" + + "\u0000\u0000\u0000\u0004date\u0000\u0000\u0000\u0004etag\u0000\u0000\u0000\u0006expe" + + "ct\u0000\u0000\u0000\u0007expires\u0000\u0000\u0000\u0004from\u0000\u0000\u0000" + + "\u0004host\u0000\u0000\u0000\bif-match\u0000\u0000\u0000\u0011if-modified-since" + + "\u0000\u0000\u0000\rif-none-match\u0000\u0000\u0000\bif-range\u0000\u0000\u0000" + + "\u0013if-unmodified-since\u0000\u0000\u0000\rlast-modified\u0000\u0000\u0000\blocati" + + "on\u0000\u0000\u0000\fmax-forwards\u0000\u0000\u0000\u0006pragma\u0000\u0000\u0000" + + "\u0012proxy-authenticate\u0000\u0000\u0000\u0013proxy-authorization\u0000\u0000" + + "\u0000\u0005range\u0000\u0000\u0000\u0007referer\u0000\u0000\u0000\u000Bretry-after" + + "\u0000\u0000\u0000\u0006server\u0000\u0000\u0000\u0002te\u0000\u0000\u0000\u0007trai" + + "ler\u0000\u0000\u0000\u0011transfer-encoding\u0000\u0000\u0000\u0007upgrade\u0000" + + "\u0000\u0000\nuser-agent\u0000\u0000\u0000\u0004vary\u0000\u0000\u0000\u0003via" + + "\u0000\u0000\u0000\u0007warning\u0000\u0000\u0000\u0010www-authenticate\u0000\u0000" + + "\u0000\u0006method\u0000\u0000\u0000\u0003get\u0000\u0000\u0000\u0006status\u0000" + + "\u0000\u0000\u0006200 OK\u0000\u0000\u0000\u0007version\u0000\u0000\u0000\bHTTP/1.1" + + "\u0000\u0000\u0000\u0003url\u0000\u0000\u0000\u0006public\u0000\u0000\u0000\nset-coo" + + "kie\u0000\u0000\u0000\nkeep-alive\u0000\u0000\u0000\u0006origin100101201202205206300" + + "302303304305306307402405406407408409410411412413414415416417502504505203 Non-Authori" + + "tative Information204 No Content301 Moved Permanently400 Bad Request401 Unauthorized" + + "403 Forbidden404 Not Found500 Internal Server Error501 Not Implemented503 Service Un" + + "availableJan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec 00:00:00 Mon, Tue, Wed, Th" + + "u, Fri, Sat, Sun, GMTchunked,text/html,image/png,image/jpg,image/gif,application/xml" + + ",application/xhtml+xml,text/plain,text/javascript,publicprivatemax-age=gzip,deflate," + + "sdchcharset=utf-8charset=iso-8859-1,utf-,*,enq=0.").getBytes(Util.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(); + } + } + + @Override public FrameReader newReader(InputStream in, boolean client) { + return new Reader(in, client); + } + + @Override public FrameWriter newWriter(OutputStream out, boolean client) { + return new Writer(out, client); + } + + /** Read spdy/3 frames. */ + static final class Reader implements FrameReader { + private final DataInputStream in; + private final boolean client; + private final NameValueBlockReader nameValueBlockReader; + + Reader(InputStream in, boolean client) { + this.in = new DataInputStream(in); + this.nameValueBlockReader = new NameValueBlockReader(in); + this.client = client; + } + + @Override public void readConnectionHeader() { + } + + /** + * Send the next frame to {@code handler}. Returns true unless there are no + * more frames on the stream. + */ + @Override public boolean nextFrame(Handler handler) throws IOException { + int w1; + try { + w1 = in.readInt(); + } catch (IOException e) { + return false; // This might be a normal socket close. + } + int w2 = in.readInt(); + + boolean control = (w1 & 0x80000000) != 0; + int flags = (w2 & 0xff000000) >>> 24; + int length = (w2 & 0xffffff); + + if (control) { + int version = (w1 & 0x7fff0000) >>> 16; + int type = (w1 & 0xffff); + + if (version != 3) { + throw new ProtocolException("version != 3: " + version); + } + + switch (type) { + case TYPE_SYN_STREAM: + readSynStream(handler, flags, length); + return true; + + case TYPE_SYN_REPLY: + readSynReply(handler, flags, length); + return true; + + case TYPE_RST_STREAM: + readRstStream(handler, flags, length); + return true; + + case TYPE_SETTINGS: + readSettings(handler, flags, length); + return true; + + case TYPE_NOOP: + if (length != 0) throw ioException("TYPE_NOOP length: %d != 0", length); + handler.noop(); + return true; + + case TYPE_PING: + readPing(handler, flags, length); + return true; + + case TYPE_GOAWAY: + readGoAway(handler, flags, length); + return true; + + case TYPE_HEADERS: + readHeaders(handler, flags, length); + return true; + + case TYPE_WINDOW_UPDATE: + readWindowUpdate(handler, flags, length); + return true; + + case TYPE_CREDENTIAL: + Util.skipByReading(in, length); + throw new UnsupportedOperationException("TODO"); // TODO: implement + + default: + throw new IOException("Unexpected frame"); + } + } else { + int streamId = w1 & 0x7fffffff; + boolean inFinished = (flags & FLAG_FIN) != 0; + handler.data(inFinished, streamId, in, length); + return true; + } + } + + private void readSynStream(Handler handler, int flags, int length) throws IOException { + int w1 = in.readInt(); + int w2 = in.readInt(); + int s3 = in.readShort(); + int streamId = w1 & 0x7fffffff; + int associatedStreamId = w2 & 0x7fffffff; + int priority = (s3 & 0xe000) >>> 13; + int slot = s3 & 0xff; + List nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 10); + + boolean inFinished = (flags & FLAG_FIN) != 0; + boolean outFinished = (flags & FLAG_UNIDIRECTIONAL) != 0; + handler.headers(outFinished, inFinished, streamId, associatedStreamId, priority, + nameValueBlock, HeadersMode.SPDY_SYN_STREAM); + } + + private void readSynReply(Handler handler, int flags, int length) throws IOException { + int w1 = in.readInt(); + int streamId = w1 & 0x7fffffff; + List nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 4); + boolean inFinished = (flags & FLAG_FIN) != 0; + handler.headers(false, inFinished, streamId, -1, -1, nameValueBlock, HeadersMode.SPDY_REPLY); + } + + private void readRstStream(Handler handler, int flags, int length) throws IOException { + if (length != 8) throw ioException("TYPE_RST_STREAM length: %d != 8", length); + int streamId = in.readInt() & 0x7fffffff; + int errorCodeInt = in.readInt(); + ErrorCode errorCode = ErrorCode.fromSpdy3Rst(errorCodeInt); + if (errorCode == null) { + throw ioException("TYPE_RST_STREAM unexpected error code: %d", errorCodeInt); + } + handler.rstStream(streamId, errorCode); + } + + private void readHeaders(Handler handler, int flags, int length) throws IOException { + int w1 = in.readInt(); + int streamId = w1 & 0x7fffffff; + List nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 4); + handler.headers(false, false, streamId, -1, -1, nameValueBlock, HeadersMode.SPDY_HEADERS); + } + + private void readWindowUpdate(Handler handler, int flags, int length) throws IOException { + if (length != 8) throw ioException("TYPE_WINDOW_UPDATE length: %d != 8", length); + int w1 = in.readInt(); + int w2 = in.readInt(); + int streamId = w1 & 0x7fffffff; + int deltaWindowSize = w2 & 0x7fffffff; + handler.windowUpdate(streamId, deltaWindowSize, false); + } + + private void readPing(Handler handler, int flags, int length) throws IOException { + if (length != 4) throw ioException("TYPE_PING length: %d != 4", length); + int id = in.readInt(); + boolean reply = client == ((id % 2) == 1); + handler.ping(reply, id, 0); + } + + private void readGoAway(Handler handler, int flags, int length) throws IOException { + if (length != 8) throw ioException("TYPE_GOAWAY length: %d != 8", length); + int lastGoodStreamId = in.readInt() & 0x7fffffff; + int errorCodeInt = in.readInt(); + ErrorCode errorCode = ErrorCode.fromSpdyGoAway(errorCodeInt); + if (errorCode == null) { + throw ioException("TYPE_GOAWAY unexpected error code: %d", errorCodeInt); + } + handler.goAway(lastGoodStreamId, errorCode); + } + + private void readSettings(Handler handler, int flags, int length) throws IOException { + int numberOfEntries = in.readInt(); + if (length != 4 + 8 * numberOfEntries) { + throw ioException("TYPE_SETTINGS length: %d != 4 + 8 * %d", length, numberOfEntries); + } + Settings settings = new Settings(); + for (int i = 0; i < numberOfEntries; i++) { + int w1 = in.readInt(); + int value = in.readInt(); + int idFlags = (w1 & 0xff000000) >>> 24; + int id = w1 & 0xffffff; + settings.set(id, idFlags, value); + } + boolean clearPrevious = (flags & Settings.FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) != 0; + handler.settings(clearPrevious, settings); + } + + private static IOException ioException(String message, Object... args) throws IOException { + throw new IOException(String.format(message, args)); + } + + @Override public void close() throws IOException { + Util.closeAll(in, nameValueBlockReader); + } + } + + /** Write spdy/3 frames. */ + static final class Writer implements FrameWriter { + private final DataOutputStream out; + private final ByteArrayOutputStream nameValueBlockBuffer; + private final DataOutputStream nameValueBlockOut; + private final boolean client; + + Writer(OutputStream out, boolean client) { + this.out = new DataOutputStream(out); + this.client = client; + + Deflater deflater = new Deflater(); + deflater.setDictionary(DICTIONARY); + nameValueBlockBuffer = new ByteArrayOutputStream(); + nameValueBlockOut = new DataOutputStream( + Platform.get().newDeflaterOutputStream(nameValueBlockBuffer, deflater, true)); + } + + @Override public synchronized void connectionHeader() { + // Do nothing: no connection header for SPDY/3. + } + + @Override public synchronized void flush() throws IOException { + out.flush(); + } + + @Override public synchronized void synStream(boolean outFinished, boolean inFinished, + int streamId, int associatedStreamId, int priority, int slot, List nameValueBlock) + throws IOException { + writeNameValueBlockToBuffer(nameValueBlock); + int length = 10 + nameValueBlockBuffer.size(); + int type = TYPE_SYN_STREAM; + int flags = (outFinished ? FLAG_FIN : 0) | (inFinished ? FLAG_UNIDIRECTIONAL : 0); + + int unused = 0; + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt((flags & 0xff) << 24 | length & 0xffffff); + out.writeInt(streamId & 0x7fffffff); + out.writeInt(associatedStreamId & 0x7fffffff); + out.writeShort((priority & 0x7) << 13 | (unused & 0x1f) << 8 | (slot & 0xff)); + nameValueBlockBuffer.writeTo(out); + out.flush(); + } + + @Override public synchronized void synReply( + boolean outFinished, int streamId, List nameValueBlock) throws IOException { + writeNameValueBlockToBuffer(nameValueBlock); + int type = TYPE_SYN_REPLY; + int flags = (outFinished ? FLAG_FIN : 0); + int length = nameValueBlockBuffer.size() + 4; + + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt((flags & 0xff) << 24 | length & 0xffffff); + out.writeInt(streamId & 0x7fffffff); + nameValueBlockBuffer.writeTo(out); + out.flush(); + } + + @Override public synchronized void headers(int streamId, List nameValueBlock) + throws IOException { + writeNameValueBlockToBuffer(nameValueBlock); + int flags = 0; + int type = TYPE_HEADERS; + int length = nameValueBlockBuffer.size() + 4; + + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt((flags & 0xff) << 24 | length & 0xffffff); + out.writeInt(streamId & 0x7fffffff); + nameValueBlockBuffer.writeTo(out); + out.flush(); + } + + @Override public synchronized void rstStream(int streamId, ErrorCode errorCode) + throws IOException { + if (errorCode.spdyRstCode == -1) throw new IllegalArgumentException(); + int flags = 0; + int type = TYPE_RST_STREAM; + int length = 8; + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt((flags & 0xff) << 24 | length & 0xffffff); + out.writeInt(streamId & 0x7fffffff); + out.writeInt(errorCode.spdyRstCode); + out.flush(); + } + + @Override public synchronized void data(boolean outFinished, int streamId, byte[] data) + throws IOException { + data(outFinished, streamId, data, 0, data.length); + } + + @Override public synchronized void data(boolean outFinished, int streamId, byte[] data, + int offset, int byteCount) throws IOException { + int flags = (outFinished ? FLAG_FIN : 0); + out.writeInt(streamId & 0x7fffffff); + out.writeInt((flags & 0xff) << 24 | byteCount & 0xffffff); + out.write(data, offset, byteCount); + } + + private void writeNameValueBlockToBuffer(List nameValueBlock) throws IOException { + nameValueBlockBuffer.reset(); + int numberOfPairs = nameValueBlock.size() / 2; + nameValueBlockOut.writeInt(numberOfPairs); + for (String s : nameValueBlock) { + nameValueBlockOut.writeInt(s.length()); + nameValueBlockOut.write(s.getBytes("UTF-8")); + } + nameValueBlockOut.flush(); + } + + @Override public synchronized void settings(Settings settings) throws IOException { + int type = TYPE_SETTINGS; + int flags = 0; + int size = settings.size(); + int length = 4 + size * 8; + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt((flags & 0xff) << 24 | length & 0xffffff); + out.writeInt(size); + for (int i = 0; i <= Settings.COUNT; i++) { + if (!settings.isSet(i)) continue; + int settingsFlags = settings.flags(i); + out.writeInt((settingsFlags & 0xff) << 24 | (i & 0xffffff)); + out.writeInt(settings.get(i)); + } + out.flush(); + } + + @Override public synchronized void noop() throws IOException { + int type = TYPE_NOOP; + int length = 0; + int flags = 0; + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt((flags & 0xff) << 24 | length & 0xffffff); + out.flush(); + } + + @Override public synchronized void ping(boolean reply, int payload1, int payload2) + throws IOException { + boolean payloadIsReply = client != ((payload1 % 2) == 1); + if (reply != payloadIsReply) throw new IllegalArgumentException("payload != reply"); + int type = TYPE_PING; + int flags = 0; + int length = 4; + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt((flags & 0xff) << 24 | length & 0xffffff); + out.writeInt(payload1); + out.flush(); + } + + @Override public synchronized void goAway(int lastGoodStreamId, ErrorCode errorCode) + throws IOException { + if (errorCode.spdyGoAwayCode == -1) throw new IllegalArgumentException(); + int type = TYPE_GOAWAY; + int flags = 0; + int length = 8; + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt((flags & 0xff) << 24 | length & 0xffffff); + out.writeInt(lastGoodStreamId); + out.writeInt(errorCode.spdyGoAwayCode); + out.flush(); + } + + @Override public synchronized void windowUpdate(int streamId, int deltaWindowSize) + throws IOException { + int type = TYPE_WINDOW_UPDATE; + int flags = 0; + int length = 8; + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt((flags & 0xff) << 24 | length & 0xffffff); + out.writeInt(streamId); + out.writeInt(deltaWindowSize); + out.flush(); + } + + @Override public void close() throws IOException { + Util.closeAll(out, nameValueBlockOut); + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/SpdyConnection.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/SpdyConnection.java new file mode 100755 index 0000000..41724f0 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/SpdyConnection.java @@ -0,0 +1,599 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.spdy; + +import com.squareup.okhttp.internal.NamedRunnable; +import com.squareup.okhttp.internal.Util; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * A socket connection to a remote peer. A connection hosts streams which can + * send and receive data. + * + *

Many methods in this API are synchronous: the call is + * completed before the method returns. This is typical for Java but atypical + * for SPDY. This is motivated by exception transparency: an IOException that + * was triggered by a certain caller can be caught and handled by that caller. + */ +public final class SpdyConnection implements Closeable { + + // Internal state of this connection is guarded by 'this'. No blocking + // operations may be performed while holding this lock! + // + // Socket writes are guarded by frameWriter. + // + // Socket reads are unguarded but are only made by the reader thread. + // + // Certain operations (like SYN_STREAM) need to synchronize on both the + // frameWriter (to do blocking I/O) and this (to create streams). Such + // operations must synchronize on 'this' last. This ensures that we never + // wait for a blocking operation while holding 'this'. + + private static final ExecutorService executor = new ThreadPoolExecutor(0, + Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue(), + Util.daemonThreadFactory("OkHttp SpdyConnection")); + + /** The protocol variant, like SPDY/3 or HTTP-draft-06/2.0. */ + final Variant variant; + + /** True if this peer initiated the connection. */ + final boolean client; + + /** + * User code to run in response to an incoming stream. Callbacks must not be + * run on the callback executor. + */ + private final IncomingStreamHandler handler; + private final FrameReader frameReader; + private final FrameWriter frameWriter; + + private final Map streams = new HashMap(); + private final String hostName; + private int lastGoodStreamId; + private int nextStreamId; + private boolean shutdown; + private long idleStartTimeNs = System.nanoTime(); + + /** Lazily-created map of in-flight pings awaiting a response. Guarded by this. */ + private Map pings; + private int nextPingId; + + /** Lazily-created settings for the peer. */ + Settings settings; + + private SpdyConnection(Builder builder) { + variant = builder.variant; + client = builder.client; + handler = builder.handler; + frameReader = variant.newReader(builder.in, client); + frameWriter = variant.newWriter(builder.out, client); + nextStreamId = builder.client ? 1 : 2; + nextPingId = builder.client ? 1 : 2; + + hostName = builder.hostName; + + new Thread(new Reader(), "Spdy Reader " + hostName).start(); + } + + /** + * Returns the number of {@link SpdyStream#isOpen() open streams} on this + * connection. + */ + public synchronized int openStreamCount() { + return streams.size(); + } + + private synchronized SpdyStream getStream(int id) { + return streams.get(id); + } + + synchronized SpdyStream removeStream(int streamId) { + SpdyStream stream = streams.remove(streamId); + if (stream != null && streams.isEmpty()) { + setIdle(true); + } + return stream; + } + + private synchronized void setIdle(boolean value) { + idleStartTimeNs = value ? System.nanoTime() : Long.MAX_VALUE; + } + + /** Returns true if this connection is idle. */ + public synchronized boolean isIdle() { + return idleStartTimeNs != Long.MAX_VALUE; + } + + /** + * Returns the time in ns when this connection became idle or Long.MAX_VALUE + * if connection is not idle. + */ + public synchronized long getIdleStartTimeNs() { + return idleStartTimeNs; + } + + /** + * Returns a new locally-initiated stream. + * + * @param out true to create an output stream that we can use to send data + * to the remote peer. Corresponds to {@code FLAG_FIN}. + * @param in true to create an input stream that the remote peer can use to + * send data to us. Corresponds to {@code FLAG_UNIDIRECTIONAL}. + */ + public SpdyStream newStream(List requestHeaders, boolean out, boolean in) + throws IOException { + boolean outFinished = !out; + boolean inFinished = !in; + int associatedStreamId = 0; // TODO: permit the caller to specify an associated stream? + int priority = 0; // TODO: permit the caller to specify a priority? + int slot = 0; // TODO: permit the caller to specify a slot? + SpdyStream stream; + int streamId; + + synchronized (frameWriter) { + synchronized (this) { + if (shutdown) { + throw new IOException("shutdown"); + } + streamId = nextStreamId; + nextStreamId += 2; + stream = new SpdyStream( + streamId, this, outFinished, inFinished, priority, requestHeaders, settings); + if (stream.isOpen()) { + streams.put(streamId, stream); + setIdle(false); + } + } + + frameWriter.synStream(outFinished, inFinished, streamId, associatedStreamId, priority, slot, + requestHeaders); + } + + return stream; + } + + void writeSynReply(int streamId, boolean outFinished, List alternating) + throws IOException { + frameWriter.synReply(outFinished, streamId, alternating); + } + + public void writeData(int streamId, boolean outFinished, byte[] buffer, int offset, int byteCount) + throws IOException { + frameWriter.data(outFinished, streamId, buffer, offset, byteCount); + } + + void writeSynResetLater(final int streamId, final ErrorCode errorCode) { + executor.submit(new NamedRunnable("OkHttp SPDY Writer %s stream %d", hostName, streamId) { + @Override public void execute() { + try { + writeSynReset(streamId, errorCode); + } catch (IOException ignored) { + } + } + }); + } + + void writeSynReset(int streamId, ErrorCode statusCode) throws IOException { + frameWriter.rstStream(streamId, statusCode); + } + + void writeWindowUpdateLater(final int streamId, final int deltaWindowSize) { + executor.submit(new NamedRunnable("OkHttp SPDY Writer %s stream %d", hostName, streamId) { + @Override public void execute() { + try { + writeWindowUpdate(streamId, deltaWindowSize); + } catch (IOException ignored) { + } + } + }); + } + + void writeWindowUpdate(int streamId, int deltaWindowSize) throws IOException { + frameWriter.windowUpdate(streamId, deltaWindowSize); + } + + /** + * Sends a ping frame to the peer. Use the returned object to await the + * ping's response and observe its round trip time. + */ + public Ping ping() throws IOException { + Ping ping = new Ping(); + int pingId; + synchronized (this) { + if (shutdown) { + throw new IOException("shutdown"); + } + pingId = nextPingId; + nextPingId += 2; + if (pings == null) pings = new HashMap(); + pings.put(pingId, ping); + } + writePing(false, pingId, 0x4f4b6f6b /* ASCII "OKok" */, ping); + return ping; + } + + private void writePingLater( + final boolean reply, final int payload1, final int payload2, final Ping ping) { + executor.submit(new NamedRunnable("OkHttp SPDY Writer %s ping %08x%08x", + hostName, payload1, payload2) { + @Override public void execute() { + try { + writePing(reply, payload1, payload2, ping); + } catch (IOException ignored) { + } + } + }); + } + + private void writePing(boolean reply, int payload1, int payload2, Ping ping) throws IOException { + synchronized (frameWriter) { + // Observe the sent time immediately before performing I/O. + if (ping != null) ping.send(); + frameWriter.ping(reply, payload1, payload2); + } + } + + private synchronized Ping removePing(int id) { + return pings != null ? pings.remove(id) : null; + } + + /** Sends a noop frame to the peer. */ + public void noop() throws IOException { + frameWriter.noop(); + } + + public void flush() throws IOException { + frameWriter.flush(); + } + + /** + * Degrades this connection such that new streams can neither be created + * locally, nor accepted from the remote peer. Existing streams are not + * impacted. This is intended to permit an endpoint to gracefully stop + * accepting new requests without harming previously established streams. + */ + public void shutdown(ErrorCode statusCode) throws IOException { + synchronized (frameWriter) { + int lastGoodStreamId; + synchronized (this) { + if (shutdown) { + return; + } + shutdown = true; + lastGoodStreamId = this.lastGoodStreamId; + } + frameWriter.goAway(lastGoodStreamId, statusCode); + } + } + + /** + * Closes this connection. This cancels all open streams and unanswered + * pings. It closes the underlying input and output streams and shuts down + * internal executor services. + */ + @Override public void close() throws IOException { + close(ErrorCode.NO_ERROR, ErrorCode.CANCEL); + } + + private void close(ErrorCode connectionCode, ErrorCode streamCode) throws IOException { + assert (!Thread.holdsLock(this)); + IOException thrown = null; + try { + shutdown(connectionCode); + } catch (IOException e) { + thrown = e; + } + + SpdyStream[] streamsToClose = null; + Ping[] pingsToCancel = null; + synchronized (this) { + if (!streams.isEmpty()) { + streamsToClose = streams.values().toArray(new SpdyStream[streams.size()]); + streams.clear(); + setIdle(false); + } + if (pings != null) { + pingsToCancel = pings.values().toArray(new Ping[pings.size()]); + pings = null; + } + } + + if (streamsToClose != null) { + for (SpdyStream stream : streamsToClose) { + try { + stream.close(streamCode); + } catch (IOException e) { + if (thrown != null) thrown = e; + } + } + } + + if (pingsToCancel != null) { + for (Ping ping : pingsToCancel) { + ping.cancel(); + } + } + + try { + frameReader.close(); + } catch (IOException e) { + thrown = e; + } + try { + frameWriter.close(); + } catch (IOException e) { + if (thrown == null) thrown = e; + } + + if (thrown != null) throw thrown; + } + + /** + * Sends a connection header if the current variant requires it. This should + * be called after {@link Builder#build} for all new connections. + */ + public void sendConnectionHeader() throws IOException { + frameWriter.connectionHeader(); + frameWriter.settings(new Settings()); + } + + /** + * Reads a connection header if the current variant requires it. This should + * be called after {@link Builder#build} for all new connections. + */ + public void readConnectionHeader() throws IOException { + frameReader.readConnectionHeader(); + } + + public static class Builder { + private String hostName; + private InputStream in; + private OutputStream out; + private IncomingStreamHandler handler = IncomingStreamHandler.REFUSE_INCOMING_STREAMS; + private Variant variant = Variant.SPDY3; + private boolean client; + + public Builder(boolean client, Socket socket) throws IOException { + this("", client, socket.getInputStream(), socket.getOutputStream()); + } + + public Builder(boolean client, InputStream in, OutputStream out) { + this("", client, in, out); + } + + /** + * @param client true if this peer initiated the connection; false if + * this peer accepted the connection. + */ + public Builder(String hostName, boolean client, Socket socket) throws IOException { + this(hostName, client, socket.getInputStream(), socket.getOutputStream()); + } + + /** + * @param client true if this peer initiated the connection; false if this + * peer accepted the connection. + */ + public Builder(String hostName, boolean client, InputStream in, OutputStream out) { + this.hostName = hostName; + this.client = client; + this.in = in; + this.out = out; + } + + public Builder handler(IncomingStreamHandler handler) { + this.handler = handler; + return this; + } + + public Builder spdy3() { + this.variant = Variant.SPDY3; + return this; + } + + public Builder http20Draft06() { + this.variant = Variant.HTTP_20_DRAFT_06; + return this; + } + + public SpdyConnection build() { + return new SpdyConnection(this); + } + } + + private class Reader implements Runnable, FrameReader.Handler { + @Override public void run() { + ErrorCode connectionErrorCode = ErrorCode.INTERNAL_ERROR; + ErrorCode streamErrorCode = ErrorCode.INTERNAL_ERROR; + try { + while (frameReader.nextFrame(this)) { + } + connectionErrorCode = ErrorCode.NO_ERROR; + streamErrorCode = ErrorCode.CANCEL; + } catch (IOException e) { + connectionErrorCode = ErrorCode.PROTOCOL_ERROR; + streamErrorCode = ErrorCode.PROTOCOL_ERROR; + } finally { + try { + close(connectionErrorCode, streamErrorCode); + } catch (IOException ignored) { + } + } + } + + @Override public void data(boolean inFinished, int streamId, InputStream in, int length) + throws IOException { + SpdyStream dataStream = getStream(streamId); + if (dataStream == null) { + writeSynResetLater(streamId, ErrorCode.INVALID_STREAM); + Util.skipByReading(in, length); + return; + } + dataStream.receiveData(in, length); + if (inFinished) { + dataStream.receiveFin(); + } + } + + @Override public void headers(boolean outFinished, boolean inFinished, int streamId, + int associatedStreamId, int priority, List nameValueBlock, + HeadersMode headersMode) { + SpdyStream stream; + synchronized (SpdyConnection.this) { + // If we're shutdown, don't bother with this stream. + if (shutdown) return; + + stream = getStream(streamId); + + if (stream == null) { + // The headers claim to be for an existing stream, but we don't have one. + if (headersMode.failIfStreamAbsent()) { + writeSynResetLater(streamId, ErrorCode.INVALID_STREAM); + return; + } + + // If the stream ID is less than the last created ID, assume it's already closed. + if (streamId <= lastGoodStreamId) return; + + // If the stream ID is in the client's namespace, assume it's already closed. + if (streamId % 2 == nextStreamId % 2) return; + + // Create a stream. + final SpdyStream newStream = new SpdyStream(streamId, SpdyConnection.this, outFinished, + inFinished, priority, nameValueBlock, settings); + lastGoodStreamId = streamId; + streams.put(streamId, newStream); + executor.submit(new NamedRunnable("OkHttp Callback %s stream %d", hostName, streamId) { + @Override public void execute() { + try { + handler.receive(newStream); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }); + return; + } + } + + // The headers claim to be for a new stream, but we already have one. + if (headersMode.failIfStreamPresent()) { + stream.closeLater(ErrorCode.PROTOCOL_ERROR); + removeStream(streamId); + return; + } + + // Update an existing stream. + stream.receiveHeaders(nameValueBlock, headersMode); + if (inFinished) stream.receiveFin(); + } + + @Override public void rstStream(int streamId, ErrorCode errorCode) { + SpdyStream rstStream = removeStream(streamId); + if (rstStream != null) { + rstStream.receiveRstStream(errorCode); + } + } + + @Override public void settings(boolean clearPrevious, Settings newSettings) { + SpdyStream[] streamsToNotify = null; + synchronized (SpdyConnection.this) { + if (settings == null || clearPrevious) { + settings = newSettings; + } else { + settings.merge(newSettings); + } + if (!streams.isEmpty()) { + streamsToNotify = streams.values().toArray(new SpdyStream[streams.size()]); + } + } + if (streamsToNotify != null) { + for (SpdyStream stream : streamsToNotify) { + // The synchronization here is ugly. We need to synchronize on 'this' to guard + // reads to 'settings'. We synchronize on 'stream' to guard the state change. + // And we need to acquire the 'stream' lock first, since that may block. + // TODO: this can block the reader thread until a write completes. That's bad! + synchronized (stream) { + synchronized (SpdyConnection.this) { + stream.receiveSettings(settings); + } + } + } + } + } + + @Override public void noop() { + } + + @Override public void ping(boolean reply, int payload1, int payload2) { + if (reply) { + Ping ping = removePing(payload1); + if (ping != null) { + ping.receive(); + } + } else { + // Send a reply to a client ping if this is a server and vice versa. + writePingLater(true, payload1, payload2, null); + } + } + + @Override public void goAway(int lastGoodStreamId, ErrorCode errorCode) { + synchronized (SpdyConnection.this) { + shutdown = true; + + // Fail all streams created after the last good stream ID. + for (Iterator> i = streams.entrySet().iterator(); + i.hasNext(); ) { + Map.Entry entry = i.next(); + int streamId = entry.getKey(); + if (streamId > lastGoodStreamId && entry.getValue().isLocallyInitiated()) { + entry.getValue().receiveRstStream(ErrorCode.REFUSED_STREAM); + i.remove(); + } + } + } + } + + @Override public void windowUpdate(int streamId, int deltaWindowSize, boolean endFlowControl) { + if (streamId == 0) { + // TODO: honor whole-stream flow control + return; + } + + // TODO: honor endFlowControl + SpdyStream stream = getStream(streamId); + if (stream != null) { + stream.receiveWindowUpdate(deltaWindowSize); + } + } + + @Override public void priority(int streamId, int priority) { + // TODO: honor priority. + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/SpdyStream.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/SpdyStream.java new file mode 100755 index 0000000..a3ab3a4 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/SpdyStream.java @@ -0,0 +1,684 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.spdy; + +import com.squareup.okhttp.internal.Util; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.List; + +import static com.squareup.okhttp.internal.Util.checkOffsetAndCount; + +/** A logical bidirectional stream. */ +public final class SpdyStream { + + // Internal state is guarded by this. No long-running or potentially + // blocking operations are performed while the lock is held. + + /** + * The number of unacknowledged bytes at which the input stream will send + * the peer a {@code WINDOW_UPDATE} frame. Must be less than this client's + * window size, otherwise the remote peer will stop sending data on this + * stream. (Chrome 25 uses 5 MiB.) + */ + public static final int WINDOW_UPDATE_THRESHOLD = Settings.DEFAULT_INITIAL_WINDOW_SIZE / 2; + + private final int id; + private final SpdyConnection connection; + private final int priority; + private long readTimeoutMillis = 0; + private int writeWindowSize; + + /** Headers sent by the stream initiator. Immutable and non null. */ + private final List requestHeaders; + + /** Headers sent in the stream reply. Null if reply is either not sent or not sent yet. */ + private List responseHeaders; + + private final SpdyDataInputStream in = new SpdyDataInputStream(); + private final SpdyDataOutputStream out = new SpdyDataOutputStream(); + + /** + * The reason why this stream was abnormally closed. If there are multiple + * reasons to abnormally close this stream (such as both peers closing it + * near-simultaneously) then this is the first reason known to this peer. + */ + private ErrorCode errorCode = null; + + SpdyStream(int id, SpdyConnection connection, boolean outFinished, boolean inFinished, + int priority, List requestHeaders, Settings settings) { + if (connection == null) throw new NullPointerException("connection == null"); + if (requestHeaders == null) throw new NullPointerException("requestHeaders == null"); + this.id = id; + this.connection = connection; + this.in.finished = inFinished; + this.out.finished = outFinished; + this.priority = priority; + this.requestHeaders = requestHeaders; + + setSettings(settings); + } + + /** + * Returns true if this stream is open. A stream is open until either: + *

    + *
  • A {@code SYN_RESET} frame abnormally terminates the stream. + *
  • Both input and output streams have transmitted all data and + * headers. + *
+ * Note that the input stream may continue to yield data even after a stream + * reports itself as not open. This is because input data is buffered. + */ + public synchronized boolean isOpen() { + if (errorCode != null) { + return false; + } + if ((in.finished || in.closed) && (out.finished || out.closed) && responseHeaders != null) { + return false; + } + return true; + } + + /** Returns true if this stream was created by this peer. */ + public boolean isLocallyInitiated() { + boolean streamIsClient = (id % 2 == 1); + return connection.client == streamIsClient; + } + + public SpdyConnection getConnection() { + return connection; + } + + public List getRequestHeaders() { + return requestHeaders; + } + + /** + * Returns the stream's response headers, blocking if necessary if they + * have not been received yet. + */ + public synchronized List getResponseHeaders() throws IOException { + long remaining = 0; + long start = 0; + if (readTimeoutMillis != 0) { + start = (System.nanoTime() / 1000000); + remaining = readTimeoutMillis; + } + try { + while (responseHeaders == null && errorCode == null) { + if (readTimeoutMillis == 0) { // No timeout configured. + wait(); + } else if (remaining > 0) { + wait(remaining); + remaining = start + readTimeoutMillis - (System.nanoTime() / 1000000); + } else { + throw new SocketTimeoutException("Read response header timeout. readTimeoutMillis: " + + readTimeoutMillis); + } + } + if (responseHeaders != null) { + return responseHeaders; + } + throw new IOException("stream was reset: " + errorCode); + } catch (InterruptedException e) { + InterruptedIOException rethrow = new InterruptedIOException(); + rethrow.initCause(e); + throw rethrow; + } + } + + /** + * Returns the reason why this stream was closed, or null if it closed + * normally or has not yet been closed. + */ + public synchronized ErrorCode getErrorCode() { + return errorCode; + } + + /** + * Sends a reply to an incoming stream. + * + * @param out true to create an output stream that we can use to send data + * to the remote peer. Corresponds to {@code FLAG_FIN}. + */ + public void reply(List responseHeaders, boolean out) throws IOException { + assert (!Thread.holdsLock(SpdyStream.this)); + boolean outFinished = false; + synchronized (this) { + if (responseHeaders == null) { + throw new NullPointerException("responseHeaders == null"); + } + if (isLocallyInitiated()) { + throw new IllegalStateException("cannot reply to a locally initiated stream"); + } + if (this.responseHeaders != null) { + throw new IllegalStateException("reply already sent"); + } + this.responseHeaders = responseHeaders; + if (!out) { + this.out.finished = true; + outFinished = true; + } + } + connection.writeSynReply(id, outFinished, responseHeaders); + } + + /** + * Sets the maximum time to wait on input stream reads before failing with a + * {@code SocketTimeoutException}, or {@code 0} to wait indefinitely. + */ + public void setReadTimeout(long readTimeoutMillis) { + this.readTimeoutMillis = readTimeoutMillis; + } + + public long getReadTimeoutMillis() { + return readTimeoutMillis; + } + + /** Returns an input stream that can be used to read data from the peer. */ + public InputStream getInputStream() { + return in; + } + + /** + * Returns an output stream that can be used to write data to the peer. + * + * @throws IllegalStateException if this stream was initiated by the peer + * and a {@link #reply} has not yet been sent. + */ + public OutputStream getOutputStream() { + synchronized (this) { + if (responseHeaders == null && !isLocallyInitiated()) { + throw new IllegalStateException("reply before requesting the output stream"); + } + } + return out; + } + + /** + * Abnormally terminate this stream. This blocks until the {@code RST_STREAM} + * frame has been transmitted. + */ + public void close(ErrorCode rstStatusCode) throws IOException { + if (!closeInternal(rstStatusCode)) { + return; // Already closed. + } + connection.writeSynReset(id, rstStatusCode); + } + + /** + * Abnormally terminate this stream. This enqueues a {@code RST_STREAM} + * frame and returns immediately. + */ + public void closeLater(ErrorCode errorCode) { + if (!closeInternal(errorCode)) { + return; // Already closed. + } + connection.writeSynResetLater(id, errorCode); + } + + /** Returns true if this stream was closed. */ + private boolean closeInternal(ErrorCode errorCode) { + assert (!Thread.holdsLock(this)); + synchronized (this) { + if (this.errorCode != null) { + return false; + } + if (in.finished && out.finished) { + return false; + } + this.errorCode = errorCode; + notifyAll(); + } + connection.removeStream(id); + return true; + } + + void receiveHeaders(List headers, HeadersMode headersMode) { + assert (!Thread.holdsLock(SpdyStream.this)); + ErrorCode errorCode = null; + boolean open = true; + synchronized (this) { + if (responseHeaders == null) { + if (headersMode.failIfHeadersAbsent()) { + errorCode = ErrorCode.PROTOCOL_ERROR; + } else { + responseHeaders = headers; + open = isOpen(); + notifyAll(); + } + } else { + if (headersMode.failIfHeadersPresent()) { + errorCode = ErrorCode.STREAM_IN_USE; + } else { + List newHeaders = new ArrayList(); + newHeaders.addAll(responseHeaders); + newHeaders.addAll(headers); + this.responseHeaders = newHeaders; + } + } + } + if (errorCode != null) { + closeLater(errorCode); + } else if (!open) { + connection.removeStream(id); + } + } + + void receiveData(InputStream in, int length) throws IOException { + assert (!Thread.holdsLock(SpdyStream.this)); + this.in.receive(in, length); + } + + void receiveFin() { + assert (!Thread.holdsLock(SpdyStream.this)); + boolean open; + synchronized (this) { + this.in.finished = true; + open = isOpen(); + notifyAll(); + } + if (!open) { + connection.removeStream(id); + } + } + + synchronized void receiveRstStream(ErrorCode errorCode) { + if (this.errorCode == null) { + this.errorCode = errorCode; + notifyAll(); + } + } + + private void setSettings(Settings settings) { + // TODO: For HTTP/2.0, also adjust the stream flow control window size + // by the difference between the new value and the old value. + assert (Thread.holdsLock(connection)); // Because 'settings' is guarded by 'connection'. + this.writeWindowSize = settings != null + ? settings.getInitialWindowSize(Settings.DEFAULT_INITIAL_WINDOW_SIZE) + : Settings.DEFAULT_INITIAL_WINDOW_SIZE; + } + + void receiveSettings(Settings settings) { + assert (Thread.holdsLock(this)); + setSettings(settings); + notifyAll(); + } + + synchronized void receiveWindowUpdate(int deltaWindowSize) { + out.unacknowledgedBytes -= deltaWindowSize; + notifyAll(); + } + + int getPriority() { + return priority; + } + + /** + * An input stream that reads the incoming data frames of a stream. Although + * this class uses synchronization to safely receive incoming data frames, + * it is not intended for use by multiple readers. + */ + private final class SpdyDataInputStream extends InputStream { + // Store incoming data bytes in a circular buffer. When the buffer is + // empty, pos == -1. Otherwise pos is the first byte to read and limit + // is the first byte to write. + // + // { - - - X X X X - - - } + // ^ ^ + // pos limit + // + // { X X X - - - - X X X } + // ^ ^ + // limit pos + + private final byte[] buffer = new byte[Settings.DEFAULT_INITIAL_WINDOW_SIZE]; + + /** the next byte to be read, or -1 if the buffer is empty. Never buffer.length */ + private int pos = -1; + + /** the last byte to be read. Never buffer.length */ + private int limit; + + /** True if the caller has closed this stream. */ + private boolean closed; + + /** + * True if either side has cleanly shut down this stream. We will + * receive no more bytes beyond those already in the buffer. + */ + private boolean finished; + + /** + * The total number of bytes consumed by the application (with {@link + * #read}), but not yet acknowledged by sending a {@code WINDOW_UPDATE} + * frame. + */ + private int unacknowledgedBytes = 0; + + @Override public int available() throws IOException { + synchronized (SpdyStream.this) { + checkNotClosed(); + if (pos == -1) { + return 0; + } else if (limit > pos) { + return limit - pos; + } else { + return limit + (buffer.length - pos); + } + } + } + + @Override public int read() throws IOException { + return Util.readSingleByte(this); + } + + @Override public int read(byte[] b, int offset, int count) throws IOException { + synchronized (SpdyStream.this) { + checkOffsetAndCount(b.length, offset, count); + waitUntilReadable(); + checkNotClosed(); + + if (pos == -1) { + return -1; + } + + int copied = 0; + + // drain from [pos..buffer.length) + if (limit <= pos) { + int bytesToCopy = Math.min(count, buffer.length - pos); + System.arraycopy(buffer, pos, b, offset, bytesToCopy); + pos += bytesToCopy; + copied += bytesToCopy; + if (pos == buffer.length) { + pos = 0; + } + } + + // drain from [pos..limit) + if (copied < count) { + int bytesToCopy = Math.min(limit - pos, count - copied); + System.arraycopy(buffer, pos, b, offset + copied, bytesToCopy); + pos += bytesToCopy; + copied += bytesToCopy; + } + + // Flow control: notify the peer that we're ready for more data! + unacknowledgedBytes += copied; + if (unacknowledgedBytes >= WINDOW_UPDATE_THRESHOLD) { + connection.writeWindowUpdateLater(id, unacknowledgedBytes); + unacknowledgedBytes = 0; + } + + if (pos == limit) { + pos = -1; + limit = 0; + } + + return copied; + } + } + + /** + * Returns once the input stream is either readable or finished. Throws + * a {@link SocketTimeoutException} if the read timeout elapses before + * that happens. + */ + private void waitUntilReadable() throws IOException { + long start = 0; + long remaining = 0; + if (readTimeoutMillis != 0) { + start = (System.nanoTime() / 1000000); + remaining = readTimeoutMillis; + } + try { + while (pos == -1 && !finished && !closed && errorCode == null) { + if (readTimeoutMillis == 0) { + SpdyStream.this.wait(); + } else if (remaining > 0) { + SpdyStream.this.wait(remaining); + remaining = start + readTimeoutMillis - (System.nanoTime() / 1000000); + } else { + throw new SocketTimeoutException(); + } + } + } catch (InterruptedException e) { + throw new InterruptedIOException(); + } + } + + void receive(InputStream in, int byteCount) throws IOException { + assert (!Thread.holdsLock(SpdyStream.this)); + + if (byteCount == 0) { + return; + } + + int pos; + int limit; + int firstNewByte; + boolean finished; + boolean flowControlError; + synchronized (SpdyStream.this) { + finished = this.finished; + pos = this.pos; + firstNewByte = this.limit; + limit = this.limit; + flowControlError = byteCount > buffer.length - available(); + } + + // If the peer sends more data than we can handle, discard it and close the connection. + if (flowControlError) { + Util.skipByReading(in, byteCount); + closeLater(ErrorCode.FLOW_CONTROL_ERROR); + return; + } + + // Discard data received after the stream is finished. It's probably a benign race. + if (finished) { + Util.skipByReading(in, byteCount); + return; + } + + // Fill the buffer without holding any locks. First fill [limit..buffer.length) if that + // won't overwrite unread data. Then fill [limit..pos). We can't hold a lock, otherwise + // writes will be blocked until reads complete. + if (pos < limit) { + int firstCopyCount = Math.min(byteCount, buffer.length - limit); + Util.readFully(in, buffer, limit, firstCopyCount); + limit += firstCopyCount; + byteCount -= firstCopyCount; + if (limit == buffer.length) { + limit = 0; + } + } + if (byteCount > 0) { + Util.readFully(in, buffer, limit, byteCount); + limit += byteCount; + } + + synchronized (SpdyStream.this) { + // Update the new limit, and mark the position as readable if necessary. + this.limit = limit; + if (this.pos == -1) { + this.pos = firstNewByte; + SpdyStream.this.notifyAll(); + } + } + } + + @Override public void close() throws IOException { + synchronized (SpdyStream.this) { + closed = true; + SpdyStream.this.notifyAll(); + } + cancelStreamIfNecessary(); + } + + private void checkNotClosed() throws IOException { + if (closed) { + throw new IOException("stream closed"); + } + if (errorCode != null) { + throw new IOException("stream was reset: " + errorCode); + } + } + } + + private void cancelStreamIfNecessary() throws IOException { + assert (!Thread.holdsLock(SpdyStream.this)); + boolean open; + boolean cancel; + synchronized (this) { + cancel = !in.finished && in.closed && (out.finished || out.closed); + open = isOpen(); + } + if (cancel) { + // RST this stream to prevent additional data from being sent. This + // is safe because the input stream is closed (we won't use any + // further bytes) and the output stream is either finished or closed + // (so RSTing both streams doesn't cause harm). + SpdyStream.this.close(ErrorCode.CANCEL); + } else if (!open) { + connection.removeStream(id); + } + } + + /** + * An output stream that writes outgoing data frames of a stream. This class + * is not thread safe. + */ + private final class SpdyDataOutputStream extends OutputStream { + private final byte[] buffer = new byte[8192]; + private int pos = 0; + + /** True if the caller has closed this stream. */ + private boolean closed; + + /** + * True if either side has cleanly shut down this stream. We shall send + * no more bytes. + */ + private boolean finished; + + /** + * The total number of bytes written out to the peer, but not yet + * acknowledged with an incoming {@code WINDOW_UPDATE} frame. Writes + * block if they cause this to exceed the {@code WINDOW_SIZE}. + */ + private int unacknowledgedBytes = 0; + + @Override public void write(int b) throws IOException { + Util.writeSingleByte(this, b); + } + + @Override public void write(byte[] bytes, int offset, int count) throws IOException { + assert (!Thread.holdsLock(SpdyStream.this)); + checkOffsetAndCount(bytes.length, offset, count); + checkNotClosed(); + + while (count > 0) { + if (pos == buffer.length) { + writeFrame(false); + } + int bytesToCopy = Math.min(count, buffer.length - pos); + System.arraycopy(bytes, offset, buffer, pos, bytesToCopy); + pos += bytesToCopy; + offset += bytesToCopy; + count -= bytesToCopy; + } + } + + @Override public void flush() throws IOException { + assert (!Thread.holdsLock(SpdyStream.this)); + checkNotClosed(); + if (pos > 0) { + writeFrame(false); + connection.flush(); + } + } + + @Override public void close() throws IOException { + assert (!Thread.holdsLock(SpdyStream.this)); + synchronized (SpdyStream.this) { + if (closed) { + return; + } + closed = true; + } + if (!out.finished) { + writeFrame(true); + } + connection.flush(); + cancelStreamIfNecessary(); + } + + private void writeFrame(boolean outFinished) throws IOException { + assert (!Thread.holdsLock(SpdyStream.this)); + + int length = pos; + synchronized (SpdyStream.this) { + waitUntilWritable(length, outFinished); + unacknowledgedBytes += length; + } + connection.writeData(id, outFinished, buffer, 0, pos); + pos = 0; + } + + /** + * Returns once the peer is ready to receive {@code count} bytes. + * + * @throws IOException if the stream was finished or closed, or the + * thread was interrupted. + */ + private void waitUntilWritable(int count, boolean last) throws IOException { + try { + while (unacknowledgedBytes + count >= writeWindowSize) { + SpdyStream.this.wait(); // Wait until we receive a WINDOW_UPDATE. + + // The stream may have been closed or reset while we were waiting! + if (!last && closed) { + throw new IOException("stream closed"); + } else if (finished) { + throw new IOException("stream finished"); + } else if (errorCode != null) { + throw new IOException("stream was reset: " + errorCode); + } + } + } catch (InterruptedException e) { + throw new InterruptedIOException(); + } + } + + private void checkNotClosed() throws IOException { + synchronized (SpdyStream.this) { + if (closed) { + throw new IOException("stream closed"); + } else if (finished) { + throw new IOException("stream finished"); + } else if (errorCode != null) { + throw new IOException("stream was reset: " + errorCode); + } + } + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Variant.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Variant.java new file mode 100755 index 0000000..8f48bcd --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/spdy/Variant.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.internal.spdy; + +import java.io.InputStream; +import java.io.OutputStream; + +/** A version and dialect of the framed socket protocol. */ +interface Variant { + Variant SPDY3 = new Spdy3(); + Variant HTTP_20_DRAFT_06 = new Http20Draft06(); + + /** + * @param client true if this is the HTTP client's reader, reading frames from + * a peer SPDY or HTTP/2 server. + */ + FrameReader newReader(InputStream in, boolean client); + + /** + * @param client true if this is the HTTP client's writer, writing frames to a + * peer SPDY or HTTP/2 server. + */ + FrameWriter newWriter(OutputStream out, boolean client); +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/tls/DistinguishedNameParser.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/tls/DistinguishedNameParser.java new file mode 100755 index 0000000..e0aef14 --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/tls/DistinguishedNameParser.java @@ -0,0 +1,407 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.tls; + +import javax.security.auth.x500.X500Principal; + +/** + * A distinguished name (DN) parser. This parser only supports extracting a + * string value from a DN. It doesn't support values in the hex-string style. + */ +final class DistinguishedNameParser { + private final String dn; + private final int length; + private int pos; + private int beg; + private int end; + + /** Temporary variable to store positions of the currently parsed item. */ + private int cur; + + /** Distinguished name characters. */ + private char[] chars; + + public DistinguishedNameParser(X500Principal principal) { + // RFC2253 is used to ensure we get attributes in the reverse + // order of the underlying ASN.1 encoding, so that the most + // significant values of repeated attributes occur first. + this.dn = principal.getName(X500Principal.RFC2253); + this.length = this.dn.length(); + } + + // gets next attribute type: (ALPHA 1*keychar) / oid + private String nextAT() { + // skip preceding space chars, they can present after + // comma or semicolon (compatibility with RFC 1779) + for (; pos < length && chars[pos] == ' '; pos++) { + } + if (pos == length) { + return null; // reached the end of DN + } + + // mark the beginning of attribute type + beg = pos; + + // attribute type chars + pos++; + for (; pos < length && chars[pos] != '=' && chars[pos] != ' '; pos++) { + // we don't follow exact BNF syntax here: + // accept any char except space and '=' + } + if (pos >= length) { + throw new IllegalStateException("Unexpected end of DN: " + dn); + } + + // mark the end of attribute type + end = pos; + + // skip trailing space chars between attribute type and '=' + // (compatibility with RFC 1779) + if (chars[pos] == ' ') { + for (; pos < length && chars[pos] != '=' && chars[pos] == ' '; pos++) { + } + + if (chars[pos] != '=' || pos == length) { + throw new IllegalStateException("Unexpected end of DN: " + dn); + } + } + + pos++; //skip '=' char + + // skip space chars between '=' and attribute value + // (compatibility with RFC 1779) + for (; pos < length && chars[pos] == ' '; pos++) { + } + + // in case of oid attribute type skip its prefix: "oid." or "OID." + // (compatibility with RFC 1779) + if ((end - beg > 4) && (chars[beg + 3] == '.') + && (chars[beg] == 'O' || chars[beg] == 'o') + && (chars[beg + 1] == 'I' || chars[beg + 1] == 'i') + && (chars[beg + 2] == 'D' || chars[beg + 2] == 'd')) { + beg += 4; + } + + return new String(chars, beg, end - beg); + } + + // gets quoted attribute value: QUOTATION *( quotechar / pair ) QUOTATION + private String quotedAV() { + pos++; + beg = pos; + end = beg; + while (true) { + + if (pos == length) { + throw new IllegalStateException("Unexpected end of DN: " + dn); + } + + if (chars[pos] == '"') { + // enclosing quotation was found + pos++; + break; + } else if (chars[pos] == '\\') { + chars[end] = getEscaped(); + } else { + // shift char: required for string with escaped chars + chars[end] = chars[pos]; + } + pos++; + end++; + } + + // skip trailing space chars before comma or semicolon. + // (compatibility with RFC 1779) + for (; pos < length && chars[pos] == ' '; pos++) { + } + + return new String(chars, beg, end - beg); + } + + // gets hex string attribute value: "#" hexstring + private String hexAV() { + if (pos + 4 >= length) { + // encoded byte array must be not less then 4 c + throw new IllegalStateException("Unexpected end of DN: " + dn); + } + + beg = pos; // store '#' position + pos++; + while (true) { + + // check for end of attribute value + // looks for space and component separators + if (pos == length || chars[pos] == '+' || chars[pos] == ',' + || chars[pos] == ';') { + end = pos; + break; + } + + if (chars[pos] == ' ') { + end = pos; + pos++; + // skip trailing space chars before comma or semicolon. + // (compatibility with RFC 1779) + for (; pos < length && chars[pos] == ' '; pos++) { + } + break; + } else if (chars[pos] >= 'A' && chars[pos] <= 'F') { + chars[pos] += 32; //to low case + } + + pos++; + } + + // verify length of hex string + // encoded byte array must be not less then 4 and must be even number + int hexLen = end - beg; // skip first '#' char + if (hexLen < 5 || (hexLen & 1) == 0) { + throw new IllegalStateException("Unexpected end of DN: " + dn); + } + + // get byte encoding from string representation + byte[] encoded = new byte[hexLen / 2]; + for (int i = 0, p = beg + 1; i < encoded.length; p += 2, i++) { + encoded[i] = (byte) getByte(p); + } + + return new String(chars, beg, hexLen); + } + + // gets string attribute value: *( stringchar / pair ) + private String escapedAV() { + beg = pos; + end = pos; + while (true) { + if (pos >= length) { + // the end of DN has been found + return new String(chars, beg, end - beg); + } + + switch (chars[pos]) { + case '+': + case ',': + case ';': + // separator char has been found + return new String(chars, beg, end - beg); + case '\\': + // escaped char + chars[end++] = getEscaped(); + pos++; + break; + case ' ': + // need to figure out whether space defines + // the end of attribute value or not + cur = end; + + pos++; + chars[end++] = ' '; + + for (; pos < length && chars[pos] == ' '; pos++) { + chars[end++] = ' '; + } + if (pos == length || chars[pos] == ',' || chars[pos] == '+' + || chars[pos] == ';') { + // separator char or the end of DN has been found + return new String(chars, beg, cur - beg); + } + break; + default: + chars[end++] = chars[pos]; + pos++; + } + } + } + + // returns escaped char + private char getEscaped() { + pos++; + if (pos == length) { + throw new IllegalStateException("Unexpected end of DN: " + dn); + } + + switch (chars[pos]) { + case '"': + case '\\': + case ',': + case '=': + case '+': + case '<': + case '>': + case '#': + case ';': + case ' ': + case '*': + case '%': + case '_': + //FIXME: escaping is allowed only for leading or trailing space char + return chars[pos]; + default: + // RFC doesn't explicitly say that escaped hex pair is + // interpreted as UTF-8 char. It only contains an example of such DN. + return getUTF8(); + } + } + + // decodes UTF-8 char + // see http://www.unicode.org for UTF-8 bit distribution table + private char getUTF8() { + int res = getByte(pos); + pos++; //FIXME tmp + + if (res < 128) { // one byte: 0-7F + return (char) res; + } else if (res >= 192 && res <= 247) { + + int count; + if (res <= 223) { // two bytes: C0-DF + count = 1; + res = res & 0x1F; + } else if (res <= 239) { // three bytes: E0-EF + count = 2; + res = res & 0x0F; + } else { // four bytes: F0-F7 + count = 3; + res = res & 0x07; + } + + int b; + for (int i = 0; i < count; i++) { + pos++; + if (pos == length || chars[pos] != '\\') { + return 0x3F; //FIXME failed to decode UTF-8 char - return '?' + } + pos++; + + b = getByte(pos); + pos++; //FIXME tmp + if ((b & 0xC0) != 0x80) { + return 0x3F; //FIXME failed to decode UTF-8 char - return '?' + } + + res = (res << 6) + (b & 0x3F); + } + return (char) res; + } else { + return 0x3F; //FIXME failed to decode UTF-8 char - return '?' + } + } + + // Returns byte representation of a char pair + // The char pair is composed of DN char in + // specified 'position' and the next char + // According to BNF syntax: + // hexchar = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" + // / "a" / "b" / "c" / "d" / "e" / "f" + private int getByte(int position) { + if (position + 1 >= length) { + throw new IllegalStateException("Malformed DN: " + dn); + } + + int b1, b2; + + b1 = chars[position]; + if (b1 >= '0' && b1 <= '9') { + b1 = b1 - '0'; + } else if (b1 >= 'a' && b1 <= 'f') { + b1 = b1 - 87; // 87 = 'a' - 10 + } else if (b1 >= 'A' && b1 <= 'F') { + b1 = b1 - 55; // 55 = 'A' - 10 + } else { + throw new IllegalStateException("Malformed DN: " + dn); + } + + b2 = chars[position + 1]; + if (b2 >= '0' && b2 <= '9') { + b2 = b2 - '0'; + } else if (b2 >= 'a' && b2 <= 'f') { + b2 = b2 - 87; // 87 = 'a' - 10 + } else if (b2 >= 'A' && b2 <= 'F') { + b2 = b2 - 55; // 55 = 'A' - 10 + } else { + throw new IllegalStateException("Malformed DN: " + dn); + } + + return (b1 << 4) + b2; + } + + /** + * Parses the DN and returns the most significant attribute value + * for an attribute type, or null if none found. + * + * @param attributeType attribute type to look for (e.g. "ca") + */ + public String findMostSpecific(String attributeType) { + // Initialize internal state. + pos = 0; + beg = 0; + end = 0; + cur = 0; + chars = dn.toCharArray(); + + String attType = nextAT(); + if (attType == null) { + return null; + } + while (true) { + String attValue = ""; + + if (pos == length) { + return null; + } + + switch (chars[pos]) { + case '"': + attValue = quotedAV(); + break; + case '#': + attValue = hexAV(); + break; + case '+': + case ',': + case ';': // compatibility with RFC 1779: semicolon can separate RDNs + //empty attribute value + break; + default: + attValue = escapedAV(); + } + + // Values are ordered from most specific to least specific + // due to the RFC2253 formatting. So take the first match + // we see. + if (attributeType.equalsIgnoreCase(attType)) { + return attValue; + } + + if (pos >= length) { + return null; + } + + if (chars[pos] == ',' || chars[pos] == ';') { + } else if (chars[pos] != '+') { + throw new IllegalStateException("Malformed DN: " + dn); + } + + pos++; + attType = nextAT(); + if (attType == null) { + throw new IllegalStateException("Malformed DN: " + dn); + } + } + } +} diff --git a/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/tls/OkHostnameVerifier.java b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/tls/OkHostnameVerifier.java new file mode 100755 index 0000000..a08773f --- /dev/null +++ b/platforms/android/CordovaLib/src/com/squareup/okhttp/internal/tls/OkHostnameVerifier.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.squareup.okhttp.internal.tls; + +import java.security.cert.Certificate; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.security.auth.x500.X500Principal; + +/** + * A HostnameVerifier consistent with RFC 2818. + */ +public final class OkHostnameVerifier implements HostnameVerifier { + public static final OkHostnameVerifier INSTANCE = new OkHostnameVerifier(); + + /** + * Quick and dirty pattern to differentiate IP addresses from hostnames. This + * is an approximation of Android's private InetAddress#isNumeric API. + * + *

This matches IPv6 addresses as a hex string containing at least one + * colon, and possibly including dots after the first colon. It matches IPv4 + * addresses as strings containing only decimal digits and dots. This pattern + * matches strings like "a:.23" and "54" that are neither IP addresses nor + * hostnames; they will be verified as IP addresses (which is a more strict + * verification). + */ + private static final Pattern VERIFY_AS_IP_ADDRESS = Pattern.compile( + "([0-9a-fA-F]*:[0-9a-fA-F:.]*)|([\\d.]+)"); + + private static final int ALT_DNS_NAME = 2; + private static final int ALT_IPA_NAME = 7; + + private OkHostnameVerifier() { + } + + public boolean verify(String host, SSLSession session) { + try { + Certificate[] certificates = session.getPeerCertificates(); + return verify(host, (X509Certificate) certificates[0]); + } catch (SSLException e) { + return false; + } + } + + public boolean verify(String host, X509Certificate certificate) { + return verifyAsIpAddress(host) + ? verifyIpAddress(host, certificate) + : verifyHostName(host, certificate); + } + + static boolean verifyAsIpAddress(String host) { + return VERIFY_AS_IP_ADDRESS.matcher(host).matches(); + } + + /** + * Returns true if {@code certificate} matches {@code ipAddress}. + */ + private boolean verifyIpAddress(String ipAddress, X509Certificate certificate) { + for (String altName : getSubjectAltNames(certificate, ALT_IPA_NAME)) { + if (ipAddress.equalsIgnoreCase(altName)) { + return true; + } + } + return false; + } + + /** + * Returns true if {@code certificate} matches {@code hostName}. + */ + private boolean verifyHostName(String hostName, X509Certificate certificate) { + hostName = hostName.toLowerCase(Locale.US); + boolean hasDns = false; + for (String altName : getSubjectAltNames(certificate, ALT_DNS_NAME)) { + hasDns = true; + if (verifyHostName(hostName, altName)) { + return true; + } + } + + if (!hasDns) { + X500Principal principal = certificate.getSubjectX500Principal(); + // RFC 2818 advises using the most specific name for matching. + String cn = new DistinguishedNameParser(principal).findMostSpecific("cn"); + if (cn != null) { + return verifyHostName(hostName, cn); + } + } + + return false; + } + + private List getSubjectAltNames(X509Certificate certificate, int type) { + List result = new ArrayList(); + try { + Collection subjectAltNames = certificate.getSubjectAlternativeNames(); + if (subjectAltNames == null) { + return Collections.emptyList(); + } + for (Object subjectAltName : subjectAltNames) { + List entry = (List) subjectAltName; + if (entry == null || entry.size() < 2) { + continue; + } + Integer altNameType = (Integer) entry.get(0); + if (altNameType == null) { + continue; + } + if (altNameType == type) { + String altName = (String) entry.get(1); + if (altName != null) { + result.add(altName); + } + } + } + return result; + } catch (CertificateParsingException e) { + return Collections.emptyList(); + } + } + + /** + * Returns true if {@code hostName} matches the name or pattern {@code cn}. + * + * @param hostName lowercase host name. + * @param cn certificate host name. May include wildcards like + * {@code *.android.com}. + */ + public boolean verifyHostName(String hostName, String cn) { + // Check length == 0 instead of .isEmpty() to support Java 5. + if (hostName == null || hostName.length() == 0 || cn == null || cn.length() == 0) { + return false; + } + + cn = cn.toLowerCase(Locale.US); + + if (!cn.contains("*")) { + return hostName.equals(cn); + } + + if (cn.startsWith("*.") && hostName.regionMatches(0, cn, 2, cn.length() - 2)) { + return true; // "*.foo.com" matches "foo.com" + } + + int asterisk = cn.indexOf('*'); + int dot = cn.indexOf('.'); + if (asterisk > dot) { + return false; // malformed; wildcard must be in the first part of the cn + } + + if (!hostName.regionMatches(0, cn, 0, asterisk)) { + return false; // prefix before '*' doesn't match + } + + int suffixLength = cn.length() - (asterisk + 1); + int suffixStart = hostName.length() - suffixLength; + if (hostName.indexOf('.', asterisk) < suffixStart) { + // TODO: remove workaround for *.clients.google.com http://b/5426333 + if (!hostName.endsWith(".clients.google.com")) { + return false; // wildcard '*' can't match a '.' + } + } + + if (!hostName.regionMatches(suffixStart, cn, asterisk + 1, suffixLength)) { + return false; // suffix after '*' doesn't match + } + + return true; + } +} diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/App.java b/platforms/android/CordovaLib/src/org/apache/cordova/App.java new file mode 100755 index 0000000..160923c --- /dev/null +++ b/platforms/android/CordovaLib/src/org/apache/cordova/App.java @@ -0,0 +1,301 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +package org.apache.cordova; + +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.LOG; +import org.apache.cordova.PluginResult; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.telephony.TelephonyManager; +import android.view.KeyEvent; + +import java.util.HashMap; + +/** + * This class exposes methods in Cordova that can be called from JavaScript. + */ +public class App extends CordovaPlugin { + + protected static final String TAG = "CordovaApp"; + private BroadcastReceiver telephonyReceiver; + + /** + * Sets the context of the Command. This can then be used to do things like + * get file paths associated with the Activity. + */ + @Override + public void pluginInitialize() { + this.initTelephonyReceiver(); + } + + /** + * Executes the request and returns PluginResult. + * + * @param action The action to execute. + * @param args JSONArry of arguments for the plugin. + * @param callbackContext The callback context from which we were invoked. + * @return A PluginResult object with a status and message. + */ + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + PluginResult.Status status = PluginResult.Status.OK; + String result = ""; + + try { + if (action.equals("clearCache")) { + this.clearCache(); + } + else if (action.equals("show")) { + // This gets called from JavaScript onCordovaReady to show the webview. + // I recommend we change the name of the Message as spinner/stop is not + // indicative of what this actually does (shows the webview). + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + webView.postMessage("spinner", "stop"); + } + }); + } + else if (action.equals("loadUrl")) { + this.loadUrl(args.getString(0), args.optJSONObject(1)); + } + else if (action.equals("cancelLoadUrl")) { + //this.cancelLoadUrl(); + } + else if (action.equals("clearHistory")) { + this.clearHistory(); + } + else if (action.equals("backHistory")) { + this.backHistory(); + } + else if (action.equals("overrideButton")) { + this.overrideButton(args.getString(0), args.getBoolean(1)); + } + else if (action.equals("overrideBackbutton")) { + this.overrideBackbutton(args.getBoolean(0)); + } + else if (action.equals("exitApp")) { + this.exitApp(); + } + callbackContext.sendPluginResult(new PluginResult(status, result)); + return true; + } catch (JSONException e) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION)); + return false; + } + } + + //-------------------------------------------------------------------------- + // LOCAL METHODS + //-------------------------------------------------------------------------- + + /** + * Clear the resource cache. + */ + public void clearCache() { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + webView.clearCache(true); + } + }); + } + + /** + * Load the url into the webview. + * + * @param url + * @param props Properties that can be passed in to the Cordova activity (i.e. loadingDialog, wait, ...) + * @throws JSONException + */ + public void loadUrl(String url, JSONObject props) throws JSONException { + LOG.d("App", "App.loadUrl("+url+","+props+")"); + int wait = 0; + boolean openExternal = false; + boolean clearHistory = false; + + // If there are properties, then set them on the Activity + HashMap params = new HashMap(); + if (props != null) { + JSONArray keys = props.names(); + for (int i = 0; i < keys.length(); i++) { + String key = keys.getString(i); + if (key.equals("wait")) { + wait = props.getInt(key); + } + else if (key.equalsIgnoreCase("openexternal")) { + openExternal = props.getBoolean(key); + } + else if (key.equalsIgnoreCase("clearhistory")) { + clearHistory = props.getBoolean(key); + } + else { + Object value = props.get(key); + if (value == null) { + + } + else if (value.getClass().equals(String.class)) { + params.put(key, (String)value); + } + else if (value.getClass().equals(Boolean.class)) { + params.put(key, (Boolean)value); + } + else if (value.getClass().equals(Integer.class)) { + params.put(key, (Integer)value); + } + } + } + } + + // If wait property, then delay loading + + if (wait > 0) { + try { + synchronized(this) { + this.wait(wait); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + this.webView.showWebPage(url, openExternal, clearHistory, params); + } + + /** + * Clear page history for the app. + */ + public void clearHistory() { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + webView.clearHistory(); + } + }); + } + + /** + * Go to previous page displayed. + * This is the same as pressing the backbutton on Android device. + */ + public void backHistory() { + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + webView.backHistory(); + } + }); + } + + /** + * Override the default behavior of the Android back button. + * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired. + * + * @param override T=override, F=cancel override + */ + public void overrideBackbutton(boolean override) { + LOG.i("App", "WARNING: Back Button Default Behavior will be overridden. The backbutton event will be fired!"); + webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override); + } + + /** + * Override the default behavior of the Android volume buttons. + * If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired. + * + * @param button volumeup, volumedown + * @param override T=override, F=cancel override + */ + public void overrideButton(String button, boolean override) { + LOG.i("App", "WARNING: Volume Button Default Behavior will be overridden. The volume event will be fired!"); + if (button.equals("volumeup")) { + webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override); + } + else if (button.equals("volumedown")) { + webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override); + } + } + + /** + * Return whether the Android back button is overridden by the user. + * + * @return boolean + */ + public boolean isBackbuttonOverridden() { + return webView.isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK); + } + + /** + * Exit the Android application. + */ + public void exitApp() { + this.webView.postMessage("exit", null); + } + + + /** + * Listen for telephony events: RINGING, OFFHOOK and IDLE + * Send these events to all plugins using + * CordovaActivity.onMessage("telephone", "ringing" | "offhook" | "idle") + */ + private void initTelephonyReceiver() { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); + //final CordovaInterface mycordova = this.cordova; + this.telephonyReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + + // If state has changed + if ((intent != null) && intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { + if (intent.hasExtra(TelephonyManager.EXTRA_STATE)) { + String extraData = intent.getStringExtra(TelephonyManager.EXTRA_STATE); + if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) { + LOG.i(TAG, "Telephone RINGING"); + webView.postMessage("telephone", "ringing"); + } + else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) { + LOG.i(TAG, "Telephone OFFHOOK"); + webView.postMessage("telephone", "offhook"); + } + else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) { + LOG.i(TAG, "Telephone IDLE"); + webView.postMessage("telephone", "idle"); + } + } + } + } + }; + + // Register the receiver + this.cordova.getActivity().registerReceiver(this.telephonyReceiver, intentFilter); + } + + /* + * Unregister the receiver + * + */ + public void onDestroy() + { + this.cordova.getActivity().unregisterReceiver(this.telephonyReceiver); + } +} diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java b/platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java new file mode 100644 index 0000000..d3a231a --- /dev/null +++ b/platforms/android/CordovaLib/src/org/apache/cordova/AuthenticationToken.java @@ -0,0 +1,69 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +package org.apache.cordova; + +/** + * The Class AuthenticationToken defines the userName and password to be used for authenticating a web resource + */ +public class AuthenticationToken { + private String userName; + private String password; + + /** + * Gets the user name. + * + * @return the user name + */ + public String getUserName() { + return userName; + } + + /** + * Sets the user name. + * + * @param userName + * the new user name + */ + public void setUserName(String userName) { + this.userName = userName; + } + + /** + * Gets the password. + * + * @return the password + */ + public String getPassword() { + return password; + } + + /** + * Sets the password. + * + * @param password + * the new password + */ + public void setPassword(String password) { + this.password = password; + } + + + + +} diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java b/platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java new file mode 100644 index 0000000..446c37d --- /dev/null +++ b/platforms/android/CordovaLib/src/org/apache/cordova/CallbackContext.java @@ -0,0 +1,144 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +package org.apache.cordova; + +import org.json.JSONArray; + +import android.util.Log; + +import org.apache.cordova.CordovaWebView; +import org.apache.cordova.PluginResult; +import org.json.JSONObject; + +public class CallbackContext { + private static final String LOG_TAG = "CordovaPlugin"; + + private String callbackId; + private CordovaWebView webView; + private boolean finished; + private int changingThreads; + + public CallbackContext(String callbackId, CordovaWebView webView) { + this.callbackId = callbackId; + this.webView = webView; + } + + public boolean isFinished() { + return finished; + } + + public boolean isChangingThreads() { + return changingThreads > 0; + } + + public String getCallbackId() { + return callbackId; + } + + public void sendPluginResult(PluginResult pluginResult) { + synchronized (this) { + if (finished) { + Log.w(LOG_TAG, "Attempted to send a second callback for ID: " + callbackId + "\nResult was: " + pluginResult.getMessage()); + return; + } else { + finished = !pluginResult.getKeepCallback(); + } + } + webView.sendPluginResult(pluginResult, callbackId); + } + + /** + * Helper for success callbacks that just returns the Status.OK by default + * + * @param message The message to add to the success result. + */ + public void success(JSONObject message) { + sendPluginResult(new PluginResult(PluginResult.Status.OK, message)); + } + + /** + * Helper for success callbacks that just returns the Status.OK by default + * + * @param message The message to add to the success result. + */ + public void success(String message) { + sendPluginResult(new PluginResult(PluginResult.Status.OK, message)); + } + + /** + * Helper for success callbacks that just returns the Status.OK by default + * + * @param message The message to add to the success result. + */ + public void success(JSONArray message) { + sendPluginResult(new PluginResult(PluginResult.Status.OK, message)); + } + + /** + * Helper for success callbacks that just returns the Status.OK by default + * + * @param message The message to add to the success result. + */ + public void success(byte[] message) { + sendPluginResult(new PluginResult(PluginResult.Status.OK, message)); + } + + /** + * Helper for success callbacks that just returns the Status.OK by default + * + * @param message The message to add to the success result. + */ + public void success(int message) { + sendPluginResult(new PluginResult(PluginResult.Status.OK, message)); + } + + /** + * Helper for success callbacks that just returns the Status.OK by default + */ + public void success() { + sendPluginResult(new PluginResult(PluginResult.Status.OK)); + } + + /** + * Helper for error callbacks that just returns the Status.ERROR by default + * + * @param message The message to add to the error result. + */ + public void error(JSONObject message) { + sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message)); + } + + /** + * Helper for error callbacks that just returns the Status.ERROR by default + * + * @param message The message to add to the error result. + */ + public void error(String message) { + sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message)); + } + + /** + * Helper for error callbacks that just returns the Status.ERROR by default + * + * @param message The message to add to the error result. + */ + public void error(int message) { + sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message)); + } +} diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/Config.java b/platforms/android/CordovaLib/src/org/apache/cordova/Config.java new file mode 100644 index 0000000..f13292c --- /dev/null +++ b/platforms/android/CordovaLib/src/org/apache/cordova/Config.java @@ -0,0 +1,122 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +package org.apache.cordova; + +import java.util.List; + +import android.app.Activity; +import android.util.Log; + +@Deprecated // Use Whitelist, CordovaPrefences, etc. directly. +public class Config { + private static final String TAG = "Config"; + + static ConfigXmlParser parser; + + private Config() { + } + + public static void init(Activity action) { + parser = new ConfigXmlParser(); + parser.parse(action); + parser.getPreferences().setPreferencesBundle(action.getIntent().getExtras()); + parser.getPreferences().copyIntoIntentExtras(action); + } + + // Intended to be used for testing only; creates an empty configuration. + public static void init() { + if (parser == null) { + parser = new ConfigXmlParser(); + } + } + + /** + * Add entry to approved list of URLs (whitelist) + * + * @param origin URL regular expression to allow + * @param subdomains T=include all subdomains under origin + */ + public static void addWhiteListEntry(String origin, boolean subdomains) { + if (parser == null) { + Log.e(TAG, "Config was not initialised. Did you forget to Config.init(this)?"); + return; + } + parser.getInternalWhitelist().addWhiteListEntry(origin, subdomains); + } + + /** + * Determine if URL is in approved list of URLs to load. + * + * @param url + * @return true if whitelisted + */ + public static boolean isUrlWhiteListed(String url) { + if (parser == null) { + Log.e(TAG, "Config was not initialised. Did you forget to Config.init(this)?"); + return false; + } + return parser.getInternalWhitelist().isUrlWhiteListed(url); + } + + /** + * Determine if URL is in approved list of URLs to launch external applications. + * + * @param url + * @return true if whitelisted + */ + public static boolean isUrlExternallyWhiteListed(String url) { + if (parser == null) { + Log.e(TAG, "Config was not initialised. Did you forget to Config.init(this)?"); + return false; + } + return parser.getExternalWhitelist().isUrlWhiteListed(url); + } + + public static String getStartUrl() { + if (parser == null) { + return "file:///android_asset/www/index.html"; + } + return parser.getLaunchUrl(); + } + + public static String getErrorUrl() { + return parser.getPreferences().getString("errorurl", null); + } + + public static Whitelist getWhitelist() { + return parser.getInternalWhitelist(); + } + + public static Whitelist getExternalWhitelist() { + return parser.getExternalWhitelist(); + } + + public static List getPluginEntries() { + return parser.getPluginEntries(); + } + + public static CordovaPreferences getPreferences() { + return parser.getPreferences(); + } + + public static boolean isInitialized() { + return parser != null; + } +} diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java b/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java new file mode 100644 index 0000000..1ada1af --- /dev/null +++ b/platforms/android/CordovaLib/src/org/apache/cordova/ConfigXmlParser.java @@ -0,0 +1,181 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +package org.apache.cordova; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.cordova.LOG; +import org.xmlpull.v1.XmlPullParserException; + +import android.app.Activity; +import android.content.res.XmlResourceParser; +import android.util.Log; + +public class ConfigXmlParser { + private static String TAG = "ConfigXmlParser"; + + private String launchUrl = "file:///android_asset/www/index.html"; + private CordovaPreferences prefs = new CordovaPreferences(); + private Whitelist internalWhitelist = new Whitelist(); + private Whitelist externalWhitelist = new Whitelist(); + private ArrayList pluginEntries = new ArrayList(20); + + public Whitelist getInternalWhitelist() { + return internalWhitelist; + } + + public Whitelist getExternalWhitelist() { + return externalWhitelist; + } + + public CordovaPreferences getPreferences() { + return prefs; + } + + public ArrayList getPluginEntries() { + return pluginEntries; + } + + public String getLaunchUrl() { + return launchUrl; + } + + public void parse(Activity action) { + // First checking the class namespace for config.xml + int id = action.getResources().getIdentifier("config", "xml", action.getClass().getPackage().getName()); + if (id == 0) { + // If we couldn't find config.xml there, we'll look in the namespace from AndroidManifest.xml + id = action.getResources().getIdentifier("config", "xml", action.getPackageName()); + if (id == 0) { + LOG.e(TAG, "res/xml/config.xml is missing!"); + return; + } + } + parse(action.getResources().getXml(id)); + } + + public void parse(XmlResourceParser xml) { + int eventType = -1; + String service = "", pluginClass = "", paramType = ""; + boolean onload = false; + boolean insideFeature = false; + ArrayList urlMap = null; + + // Add implicitly allowed URLs + internalWhitelist.addWhiteListEntry("file:///*", false); + internalWhitelist.addWhiteListEntry("content:///*", false); + internalWhitelist.addWhiteListEntry("data:*", false); + + while (eventType != XmlResourceParser.END_DOCUMENT) { + if (eventType == XmlResourceParser.START_TAG) { + String strNode = xml.getName(); + if (strNode.equals("url-filter")) { + Log.w(TAG, "Plugin " + service + " is using deprecated tag "); + if (urlMap == null) { + urlMap = new ArrayList(2); + } + urlMap.add(xml.getAttributeValue(null, "value")); + } else if (strNode.equals("feature")) { + //Check for supported feature sets aka. plugins (Accelerometer, Geolocation, etc) + //Set the bit for reading params + insideFeature = true; + service = xml.getAttributeValue(null, "name"); + } + else if (insideFeature && strNode.equals("param")) { + paramType = xml.getAttributeValue(null, "name"); + if (paramType.equals("service")) // check if it is using the older service param + service = xml.getAttributeValue(null, "value"); + else if (paramType.equals("package") || paramType.equals("android-package")) + pluginClass = xml.getAttributeValue(null,"value"); + else if (paramType.equals("onload")) + onload = "true".equals(xml.getAttributeValue(null, "value")); + } + else if (strNode.equals("access")) { + String origin = xml.getAttributeValue(null, "origin"); + String subdomains = xml.getAttributeValue(null, "subdomains"); + boolean external = (xml.getAttributeValue(null, "launch-external") != null); + if (origin != null) { + if (external) { + externalWhitelist.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0)); + } else { + if ("*".equals(origin)) { + // Special-case * origin to mean http and https when used for internal + // whitelist. This prevents external urls like sms: and geo: from being + // handled internally. + internalWhitelist.addWhiteListEntry("http://*/*", false); + internalWhitelist.addWhiteListEntry("https://*/*", false); + } else { + internalWhitelist.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0)); + } + } + } + } + else if (strNode.equals("preference")) { + String name = xml.getAttributeValue(null, "name").toLowerCase(Locale.ENGLISH); + String value = xml.getAttributeValue(null, "value"); + prefs.set(name, value); + } + else if (strNode.equals("content")) { + String src = xml.getAttributeValue(null, "src"); + if (src != null) { + setStartUrl(src); + } + } + } + else if (eventType == XmlResourceParser.END_TAG) + { + String strNode = xml.getName(); + if (strNode.equals("feature")) { + pluginEntries.add(new PluginEntry(service, pluginClass, onload, urlMap)); + + service = ""; + pluginClass = ""; + insideFeature = false; + onload = false; + urlMap = null; + } + } + try { + eventType = xml.next(); + } catch (XmlPullParserException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private void setStartUrl(String src) { + Pattern schemeRegex = Pattern.compile("^[a-z-]+://"); + Matcher matcher = schemeRegex.matcher(src); + if (matcher.find()) { + launchUrl = src; + } else { + if (src.charAt(0) == '/') { + src = src.substring(1); + } + launchUrl = "file:///android_asset/www/" + src; + } + } +} diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java new file mode 100755 index 0000000..3c12a97 --- /dev/null +++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaActivity.java @@ -0,0 +1,1063 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +package org.apache.cordova; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.apache.cordova.CordovaInterface; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.LOG; +import org.json.JSONException; +import org.json.JSONObject; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Color; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.Display; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.Window; +import android.view.WindowManager; +import android.webkit.ValueCallback; +import android.webkit.WebViewClient; +import android.widget.LinearLayout; + +/** + * This class is the main Android activity that represents the Cordova + * application. It should be extended by the user to load the specific + * html file that contains the application. + * + * As an example: + * + *

+ *     package org.apache.cordova.examples;
+ *
+ *     import android.os.Bundle;
+ *     import org.apache.cordova.*;
+ *
+ *     public class Example extends CordovaActivity {
+ *       @Override
+ *       public void onCreate(Bundle savedInstanceState) {
+ *         super.onCreate(savedInstanceState);
+ *         super.init();
+ *         // Load your application
+ *         loadUrl(launchUrl);
+ *       }
+ *     }
+ * 
+ * + * Cordova xml configuration: Cordova uses a configuration file at + * res/xml/config.xml to specify its settings. See "The config.xml File" + * guide in cordova-docs at http://cordova.apache.org/docs for the documentation + * for the configuration. The use of the set*Property() methods is + * deprecated in favor of the config.xml file. + * + */ +public class CordovaActivity extends Activity implements CordovaInterface { + public static String TAG = "CordovaActivity"; + + // The webview for our app + protected CordovaWebView appView; + + @Deprecated // unused. + protected CordovaWebViewClient webViewClient; + + @Deprecated // Will be removed. Use findViewById() to retrieve views. + protected LinearLayout root; + + protected ProgressDialog spinnerDialog = null; + private final ExecutorService threadPool = Executors.newCachedThreadPool(); + + private static int ACTIVITY_STARTING = 0; + private static int ACTIVITY_RUNNING = 1; + private static int ACTIVITY_EXITING = 2; + private int activityState = 0; // 0=starting, 1=running (after 1st resume), 2=shutting down + + // Plugin to call when activity result is received + protected CordovaPlugin activityResultCallback = null; + protected boolean activityResultKeepRunning; + + /* + * The variables below are used to cache some of the activity properties. + */ + + // Draw a splash screen using an image located in the drawable resource directory. + // This is not the same as calling super.loadSplashscreen(url) + protected int splashscreen = 0; + protected int splashscreenTime = 3000; + + // LoadUrl timeout value in msec (default of 20 sec) + protected int loadUrlTimeoutValue = 20000; + + // Keep app running when pause is received. (default = true) + // If true, then the JavaScript and native code continue to run in the background + // when another application (activity) is started. + protected boolean keepRunning = true; + + private String initCallbackClass; + + // Read from config.xml: + protected CordovaPreferences preferences; + protected Whitelist internalWhitelist; + protected Whitelist externalWhitelist; + protected String launchUrl; + protected ArrayList pluginEntries; + + /** + * Sets the authentication token. + * + * @param authenticationToken + * @param host + * @param realm + */ + public void setAuthenticationToken(AuthenticationToken authenticationToken, String host, String realm) { + if (this.appView != null && this.appView.viewClient != null) { + this.appView.viewClient.setAuthenticationToken(authenticationToken, host, realm); + } + } + + /** + * Removes the authentication token. + * + * @param host + * @param realm + * + * @return the authentication token or null if did not exist + */ + public AuthenticationToken removeAuthenticationToken(String host, String realm) { + if (this.appView != null && this.appView.viewClient != null) { + return this.appView.viewClient.removeAuthenticationToken(host, realm); + } + return null; + } + + /** + * Gets the authentication token. + * + * In order it tries: + * 1- host + realm + * 2- host + * 3- realm + * 4- no host, no realm + * + * @param host + * @param realm + * + * @return the authentication token + */ + public AuthenticationToken getAuthenticationToken(String host, String realm) { + if (this.appView != null && this.appView.viewClient != null) { + return this.appView.viewClient.getAuthenticationToken(host, realm); + } + return null; + } + + /** + * Clear all authentication tokens. + */ + public void clearAuthenticationTokens() { + if (this.appView != null && this.appView.viewClient != null) { + this.appView.viewClient.clearAuthenticationTokens(); + } + } + + /** + * Called when the activity is first created. + */ + @Override + public void onCreate(Bundle savedInstanceState) { + LOG.i(TAG, "Apache Cordova native platform version " + CordovaWebView.CORDOVA_VERSION + " is starting"); + LOG.d(TAG, "CordovaActivity.onCreate()"); + + // need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception + loadConfig(); + if(!preferences.getBoolean("ShowTitle", false)) + { + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + } + + if(preferences.getBoolean("SetFullscreen", false)) + { + Log.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version."); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } else if (preferences.getBoolean("Fullscreen", false)) { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } else { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + } + + super.onCreate(savedInstanceState); + + if(savedInstanceState != null) + { + initCallbackClass = savedInstanceState.getString("callbackClass"); + } + } + + @SuppressWarnings("deprecation") + protected void loadConfig() { + ConfigXmlParser parser = new ConfigXmlParser(); + parser.parse(this); + preferences = parser.getPreferences(); + preferences.setPreferencesBundle(getIntent().getExtras()); + preferences.copyIntoIntentExtras(this); + internalWhitelist = parser.getInternalWhitelist(); + externalWhitelist = parser.getExternalWhitelist(); + launchUrl = parser.getLaunchUrl(); + pluginEntries = parser.getPluginEntries(); + Config.parser = parser; + } + + @SuppressWarnings("deprecation") + protected void createViews() { + // This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket! + + LOG.d(TAG, "CordovaActivity.createViews()"); + + Display display = getWindowManager().getDefaultDisplay(); + int width = display.getWidth(); + int height = display.getHeight(); + + root = new LinearLayoutSoftKeyboardDetect(this, width, height); + root.setOrientation(LinearLayout.VERTICAL); + root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, 0.0F)); + + appView.setId(100); + appView.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + 1.0F)); + + // Add web view but make it invisible while loading URL + appView.setVisibility(View.INVISIBLE); + + // need to remove appView from any existing parent before invoking root.addView(appView) + ViewParent parent = appView.getParent(); + if ((parent != null) && (parent != root)) { + LOG.d(TAG, "removing appView from existing parent"); + ViewGroup parentGroup = (ViewGroup) parent; + parentGroup.removeView(appView); + } + root.addView((View) appView); + setContentView(root); + + int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK); + root.setBackgroundColor(backgroundColor); + } + + /** + * Get the Android activity. + */ + @Override public Activity getActivity() { + return this; + } + + /** + * Construct the default web view object. + * + * This is intended to be overridable by subclasses of CordovaIntent which + * require a more specialized web view. + */ + protected CordovaWebView makeWebView() { + return new CordovaWebView(CordovaActivity.this); + } + + /** + * Construct the client for the default web view object. + * + * This is intended to be overridable by subclasses of CordovaIntent which + * require a more specialized web view. + * + * @param webView the default constructed web view object + */ + protected CordovaWebViewClient makeWebViewClient(CordovaWebView webView) { + return webView.makeWebViewClient(this); + } + + /** + * Construct the chrome client for the default web view object. + * + * This is intended to be overridable by subclasses of CordovaIntent which + * require a more specialized web view. + * + * @param webView the default constructed web view object + */ + protected CordovaChromeClient makeChromeClient(CordovaWebView webView) { + return webView.makeWebChromeClient(this); + } + + public void init() { + this.init(appView, null, null); + } + + @SuppressLint("NewApi") + @Deprecated // Call init() instead and override makeWebView() to customize. + public void init(CordovaWebView webView, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient) { + LOG.d(TAG, "CordovaActivity.init()"); + + appView = webView != null ? webView : makeWebView(); + if (appView.pluginManager == null) { + appView.init(this, webViewClient != null ? webViewClient : makeWebViewClient(appView), + webChromeClient != null ? webChromeClient : makeChromeClient(appView), + pluginEntries, internalWhitelist, externalWhitelist, preferences); + } + + // TODO: Have the views set this themselves. + if (preferences.getBoolean("DisallowOverscroll", false)) { + appView.setOverScrollMode(View.OVER_SCROLL_NEVER); + } + createViews(); + + // TODO: Make this a preference (CB-6153) + // Setup the hardware volume controls to handle volume control + setVolumeControlStream(AudioManager.STREAM_MUSIC); + } + + /** + * Load the url into the webview. + */ + public void loadUrl(String url) { + if (appView == null) { + init(); + } + this.splashscreenTime = preferences.getInteger("SplashScreenDelay", this.splashscreenTime); + String splash = preferences.getString("SplashScreen", null); + if(this.splashscreenTime > 0 && splash != null) + { + this.splashscreen = getResources().getIdentifier(splash, "drawable", getClass().getPackage().getName());; + if(this.splashscreen != 0) + { + this.showSplashScreen(this.splashscreenTime); + } + } + + // If keepRunning + this.keepRunning = preferences.getBoolean("KeepRunning", true); + + //Check if the view is attached to anything + if(appView.getParent() != null) + { + // Then load the spinner + this.loadSpinner(); + } + //Load the correct splashscreen + + if(this.splashscreen != 0) + { + this.appView.loadUrl(url, this.splashscreenTime); + } + else + { + this.appView.loadUrl(url); + } + } + + /** + * Load the url into the webview after waiting for period of time. + * This is used to display the splashscreen for certain amount of time. + * + * @param url + * @param time The number of ms to wait before loading webview + */ + public void loadUrl(final String url, int time) { + + this.splashscreenTime = time; + this.loadUrl(url); + } + + /* + * Load the spinner + */ + void loadSpinner() { + + // If loadingDialog property, then show the App loading dialog for first page of app + String loading = null; + if ((this.appView == null) || !this.appView.canGoBack()) { + loading = preferences.getString("LoadingDialog", null); + } + else { + loading = preferences.getString("LoadingPageDialog", null); + } + if (loading != null) { + + String title = ""; + String message = "Loading Application..."; + + if (loading.length() > 0) { + int comma = loading.indexOf(','); + if (comma > 0) { + title = loading.substring(0, comma); + message = loading.substring(comma + 1); + } + else { + title = ""; + message = loading; + } + } + this.spinnerStart(title, message); + } + } + + @Deprecated + public void cancelLoadUrl() { + } + + /** + * Clear the resource cache. + */ + @Deprecated // Call method on appView directly. + public void clearCache() { + if (appView == null) { + init(); + } + this.appView.clearCache(true); + } + + /** + * Clear web history in this web view. + */ + @Deprecated // Call method on appView directly. + public void clearHistory() { + this.appView.clearHistory(); + } + + /** + * Go to previous page in history. (We manage our own history) + * + * @return true if we went back, false if we are already at top + */ + @Deprecated // Call method on appView directly. + public boolean backHistory() { + if (this.appView != null) { + return appView.backHistory(); + } + return false; + } + + /** + * Get boolean property for activity. + */ + @Deprecated // Call method on preferences directly. + public boolean getBooleanProperty(String name, boolean defaultValue) { + return preferences.getBoolean(name, defaultValue); + } + + /** + * Get int property for activity. + */ + @Deprecated // Call method on preferences directly. + public int getIntegerProperty(String name, int defaultValue) { + return preferences.getInteger(name, defaultValue); + } + + /** + * Get string property for activity. + */ + @Deprecated // Call method on preferences directly. + public String getStringProperty(String name, String defaultValue) { + return preferences.getString(name, defaultValue); + } + + /** + * Get double property for activity. + */ + @Deprecated // Call method on preferences directly. + public double getDoubleProperty(String name, double defaultValue) { + return preferences.getDouble(name, defaultValue); + } + + /** + * Set boolean property on activity. + * This method has been deprecated in 3.0 and will be removed at a future + * time. Please use config.xml instead. + * + * @param name + * @param value + * @deprecated + */ + @Deprecated + public void setBooleanProperty(String name, boolean value) { + Log.d(TAG, "Setting boolean properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml"); + this.getIntent().putExtra(name.toLowerCase(), value); + } + + /** + * Set int property on activity. + * This method has been deprecated in 3.0 and will be removed at a future + * time. Please use config.xml instead. + * + * @param name + * @param value + * @deprecated + */ + @Deprecated + public void setIntegerProperty(String name, int value) { + Log.d(TAG, "Setting integer properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml"); + this.getIntent().putExtra(name.toLowerCase(), value); + } + + /** + * Set string property on activity. + * This method has been deprecated in 3.0 and will be removed at a future + * time. Please use config.xml instead. + * + * @param name + * @param value + * @deprecated + */ + @Deprecated + public void setStringProperty(String name, String value) { + Log.d(TAG, "Setting string properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml"); + this.getIntent().putExtra(name.toLowerCase(), value); + } + + /** + * Set double property on activity. + * This method has been deprecated in 3.0 and will be removed at a future + * time. Please use config.xml instead. + * + * @param name + * @param value + * @deprecated + */ + @Deprecated + public void setDoubleProperty(String name, double value) { + Log.d(TAG, "Setting double properties in CordovaActivity will be deprecated in 3.0 on July 2013, please use config.xml"); + this.getIntent().putExtra(name.toLowerCase(), value); + } + + /** + * Called when the system is about to start resuming a previous activity. + */ + @Override + protected void onPause() { + super.onPause(); + + LOG.d(TAG, "Paused the application!"); + + // Don't process pause if shutting down, since onDestroy() will be called + if (this.activityState == ACTIVITY_EXITING) { + return; + } + + if (this.appView == null) { + return; + } + else + { + this.appView.handlePause(this.keepRunning); + } + + // hide the splash screen to avoid leaking a window + this.removeSplashScreen(); + } + + /** + * Called when the activity receives a new intent + **/ + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + //Forward to plugins + if (this.appView != null) + this.appView.onNewIntent(intent); + } + + /** + * Called when the activity will start interacting with the user. + */ + @Override + protected void onResume() { + super.onResume(); + LOG.d(TAG, "Resuming the App"); + + if (this.activityState == ACTIVITY_STARTING) { + this.activityState = ACTIVITY_RUNNING; + return; + } + + if (this.appView == null) { + return; + } + // Force window to have focus, so application always + // receive user input. Workaround for some devices (Samsung Galaxy Note 3 at least) + this.getWindow().getDecorView().requestFocus(); + + this.appView.handleResume(this.keepRunning, this.activityResultKeepRunning); + + // If app doesn't want to run in background + if (!this.keepRunning || this.activityResultKeepRunning) { + + // Restore multitasking state + if (this.activityResultKeepRunning) { + this.keepRunning = this.activityResultKeepRunning; + this.activityResultKeepRunning = false; + } + } + } + + /** + * The final call you receive before your activity is destroyed. + */ + @Override + public void onDestroy() { + LOG.d(TAG, "CordovaActivity.onDestroy()"); + super.onDestroy(); + + // hide the splash screen to avoid leaking a window + this.removeSplashScreen(); + + if (this.appView != null) { + appView.handleDestroy(); + } + else { + this.activityState = ACTIVITY_EXITING; + } + } + + /** + * Send a message to all plugins. + */ + public void postMessage(String id, Object data) { + if (this.appView != null) { + this.appView.postMessage(id, data); + } + } + + /** + * @deprecated + * Add services to res/xml/plugins.xml instead. + * + * Add a class that implements a service. + */ + @Deprecated + public void addService(String serviceType, String className) { + if (this.appView != null && this.appView.pluginManager != null) { + this.appView.pluginManager.addService(serviceType, className); + } + } + + /** + * Send JavaScript statement back to JavaScript. + * (This is a convenience method) + * + * @param statement + */ + @Deprecated // Call method on appView directly. + public void sendJavascript(String statement) { + if (this.appView != null) { + this.appView.bridge.getMessageQueue().addJavaScript(statement); + } + } + + /** + * Show the spinner. Must be called from the UI thread. + * + * @param title Title of the dialog + * @param message The message of the dialog + */ + public void spinnerStart(final String title, final String message) { + if (this.spinnerDialog != null) { + this.spinnerDialog.dismiss(); + this.spinnerDialog = null; + } + final CordovaActivity me = this; + this.spinnerDialog = ProgressDialog.show(CordovaActivity.this, title, message, true, true, + new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + me.spinnerDialog = null; + } + }); + } + + /** + * Stop spinner - Must be called from UI thread + */ + public void spinnerStop() { + if (this.spinnerDialog != null && this.spinnerDialog.isShowing()) { + this.spinnerDialog.dismiss(); + this.spinnerDialog = null; + } + } + + /** + * End this activity by calling finish for activity + */ + public void endActivity() { + this.activityState = ACTIVITY_EXITING; + super.finish(); + } + + + /** + * Launch an activity for which you would like a result when it finished. When this activity exits, + * your onActivityResult() method will be called. + * + * @param command The command object + * @param intent The intent to start + * @param requestCode The request code that is passed to callback to identify the activity + */ + public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode) { + this.activityResultCallback = command; + this.activityResultKeepRunning = this.keepRunning; + + // If multitasking turned on, then disable it for activities that return results + if (command != null) { + this.keepRunning = false; + } + + // Start activity + super.startActivityForResult(intent, requestCode); + } + + /** + * Called when an activity you launched exits, giving you the requestCode you started it with, + * the resultCode it returned, and any additional data from it. + * + * @param requestCode The request code originally supplied to startActivityForResult(), + * allowing you to identify who this result came from. + * @param resultCode The integer result code returned by the child activity through its setResult(). + * @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). + */ + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent intent) { + LOG.d(TAG, "Incoming Result"); + super.onActivityResult(requestCode, resultCode, intent); + Log.d(TAG, "Request code = " + requestCode); + if (appView != null && requestCode == CordovaChromeClient.FILECHOOSER_RESULTCODE) { + ValueCallback mUploadMessage = this.appView.getWebChromeClient().getValueCallback(); + Log.d(TAG, "did we get here?"); + if (null == mUploadMessage) + return; + Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData(); + Log.d(TAG, "result = " + result); + mUploadMessage.onReceiveValue(result); + mUploadMessage = null; + } + CordovaPlugin callback = this.activityResultCallback; + if(callback == null && initCallbackClass != null) { + // The application was restarted, but had defined an initial callback + // before being shut down. + this.activityResultCallback = appView.pluginManager.getPlugin(initCallbackClass); + callback = this.activityResultCallback; + } + if(callback != null) { + LOG.d(TAG, "We have a callback to send this result to"); + callback.onActivityResult(requestCode, resultCode, intent); + } + } + + public void setActivityResultCallback(CordovaPlugin plugin) { + this.activityResultCallback = plugin; + } + + /** + * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable). + * The errorCode parameter corresponds to one of the ERROR_* constants. + * + * @param errorCode The error code corresponding to an ERROR_* value. + * @param description A String describing the error. + * @param failingUrl The url that failed to load. + */ + public void onReceivedError(final int errorCode, final String description, final String failingUrl) { + final CordovaActivity me = this; + + // If errorUrl specified, then load it + final String errorUrl = preferences.getString("errorUrl", null); + if ((errorUrl != null) && (errorUrl.startsWith("file://") || internalWhitelist.isUrlWhiteListed(errorUrl)) && (!failingUrl.equals(errorUrl))) { + + // Load URL on UI thread + me.runOnUiThread(new Runnable() { + public void run() { + // Stop "app loading" spinner if showing + me.spinnerStop(); + me.appView.showWebPage(errorUrl, false, true, null); + } + }); + } + // If not, then display error dialog + else { + final boolean exit = !(errorCode == WebViewClient.ERROR_HOST_LOOKUP); + me.runOnUiThread(new Runnable() { + public void run() { + if (exit) { + me.appView.setVisibility(View.GONE); + me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit); + } + } + }); + } + } + + /** + * Display an error dialog and optionally exit application. + */ + public void displayError(final String title, final String message, final String button, final boolean exit) { + final CordovaActivity me = this; + me.runOnUiThread(new Runnable() { + public void run() { + try { + AlertDialog.Builder dlg = new AlertDialog.Builder(me); + dlg.setMessage(message); + dlg.setTitle(title); + dlg.setCancelable(false); + dlg.setPositiveButton(button, + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + if (exit) { + me.endActivity(); + } + } + }); + dlg.create(); + dlg.show(); + } catch (Exception e) { + finish(); + } + } + }); + } + + /** + * Determine if URL is in approved list of URLs to load. + */ + @Deprecated // Use whitelist object directly. + public boolean isUrlWhiteListed(String url) { + return internalWhitelist.isUrlWhiteListed(url); + } + + /* + * Hook in Cordova for menu plugins + */ + @Override + public boolean onCreateOptionsMenu(Menu menu) { + this.postMessage("onCreateOptionsMenu", menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + this.postMessage("onPrepareOptionsMenu", menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + this.postMessage("onOptionsItemSelected", item); + return true; + } + + /** + * Get Activity context. + */ + @Deprecated + public Context getContext() { + LOG.d(TAG, "This will be deprecated December 2012"); + return this; + } + + /** + * Load the specified URL in the Cordova webview or a new browser instance. + * + * NOTE: If openExternal is false, only URLs listed in whitelist can be loaded. + * + * @param url The url to load. + * @param openExternal Load url in browser instead of Cordova webview. + * @param clearHistory Clear the history stack, so new page becomes top of history + * @param params Parameters for new app + */ + @Deprecated // Call method on appView directly. + public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap params) { + if (this.appView != null) { + appView.showWebPage(url, openExternal, clearHistory, params); + } + } + + protected Dialog splashDialog; + + /** + * Removes the Dialog that displays the splash screen + */ + public void removeSplashScreen() { + if (splashDialog != null && splashDialog.isShowing()) { + splashDialog.dismiss(); + splashDialog = null; + } + } + + /** + * Shows the splash screen over the full Activity + */ + @SuppressWarnings("deprecation") + protected void showSplashScreen(final int time) { + final CordovaActivity that = this; + + Runnable runnable = new Runnable() { + public void run() { + // Get reference to display + Display display = getWindowManager().getDefaultDisplay(); + + // Create the layout for the dialog + LinearLayout root = new LinearLayout(that.getActivity()); + root.setMinimumHeight(display.getHeight()); + root.setMinimumWidth(display.getWidth()); + root.setOrientation(LinearLayout.VERTICAL); + root.setBackgroundColor(preferences.getInteger("backgroundColor", Color.BLACK)); + root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, 0.0F)); + root.setBackgroundResource(that.splashscreen); + + // Create and show the dialog + splashDialog = new Dialog(that, android.R.style.Theme_Translucent_NoTitleBar); + // check to see if the splash screen should be full screen + if ((getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) + == WindowManager.LayoutParams.FLAG_FULLSCREEN) { + splashDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + splashDialog.setContentView(root); + splashDialog.setCancelable(false); + splashDialog.show(); + + // Set Runnable to remove splash screen just in case + final Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + public void run() { + removeSplashScreen(); + } + }, time); + } + }; + this.runOnUiThread(runnable); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) + { + if (appView != null && (appView.isCustomViewShowing() || appView.getFocusedChild() != null ) && + (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) { + return appView.onKeyUp(keyCode, event); + } else { + return super.onKeyUp(keyCode, event); + } + } + + /* + * Android 2.x needs to be able to check where the cursor is. Android 4.x does not + * + * (non-Javadoc) + * @see android.app.Activity#onKeyDown(int, android.view.KeyEvent) + */ + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) + { + //Determine if the focus is on the current view or not + if (appView != null && appView.getFocusedChild() != null && (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) { + return appView.onKeyDown(keyCode, event); + } + else + return super.onKeyDown(keyCode, event); + } + + + /** + * Called when a message is sent to plugin. + * + * @param id The message id + * @param data The message data + * @return Object or null + */ + public Object onMessage(String id, Object data) { + if (!"onScrollChanged".equals(id)) { + LOG.d(TAG, "onMessage(" + id + "," + data + ")"); + } + + if ("splashscreen".equals(id)) { + if ("hide".equals(data.toString())) { + this.removeSplashScreen(); + } + else { + // If the splash dialog is showing don't try to show it again + if (this.splashDialog == null || !this.splashDialog.isShowing()) { + String splashResource = preferences.getString("SplashScreen", null); + if (splashResource != null) { + splashscreen = getResources().getIdentifier(splashResource, "drawable", getClass().getPackage().getName()); + } + this.showSplashScreen(this.splashscreenTime); + } + } + } + else if ("spinner".equals(id)) { + if ("stop".equals(data.toString())) { + this.spinnerStop(); + this.appView.setVisibility(View.VISIBLE); + } + } + else if ("onReceivedError".equals(id)) { + JSONObject d = (JSONObject) data; + try { + this.onReceivedError(d.getInt("errorCode"), d.getString("description"), d.getString("url")); + } catch (JSONException e) { + e.printStackTrace(); + } + } + else if ("exit".equals(id)) { + this.endActivity(); + } + return null; + } + + public ExecutorService getThreadPool() { + return threadPool; + } + + protected void onSaveInstanceState(Bundle outState) + { + super.onSaveInstanceState(outState); + if(this.activityResultCallback != null) + { + String cClass = this.activityResultCallback.getClass().getName(); + outState.putString("callbackClass", cClass); + } + } +} diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java new file mode 100644 index 0000000..d40d26e --- /dev/null +++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaArgs.java @@ -0,0 +1,113 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +package org.apache.cordova; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.util.Base64; + +public class CordovaArgs { + private JSONArray baseArgs; + + public CordovaArgs(JSONArray args) { + this.baseArgs = args; + } + + + // Pass through the basics to the base args. + public Object get(int index) throws JSONException { + return baseArgs.get(index); + } + + public boolean getBoolean(int index) throws JSONException { + return baseArgs.getBoolean(index); + } + + public double getDouble(int index) throws JSONException { + return baseArgs.getDouble(index); + } + + public int getInt(int index) throws JSONException { + return baseArgs.getInt(index); + } + + public JSONArray getJSONArray(int index) throws JSONException { + return baseArgs.getJSONArray(index); + } + + public JSONObject getJSONObject(int index) throws JSONException { + return baseArgs.getJSONObject(index); + } + + public long getLong(int index) throws JSONException { + return baseArgs.getLong(index); + } + + public String getString(int index) throws JSONException { + return baseArgs.getString(index); + } + + + public Object opt(int index) { + return baseArgs.opt(index); + } + + public boolean optBoolean(int index) { + return baseArgs.optBoolean(index); + } + + public double optDouble(int index) { + return baseArgs.optDouble(index); + } + + public int optInt(int index) { + return baseArgs.optInt(index); + } + + public JSONArray optJSONArray(int index) { + return baseArgs.optJSONArray(index); + } + + public JSONObject optJSONObject(int index) { + return baseArgs.optJSONObject(index); + } + + public long optLong(int index) { + return baseArgs.optLong(index); + } + + public String optString(int index) { + return baseArgs.optString(index); + } + + public boolean isNull(int index) { + return baseArgs.isNull(index); + } + + + // The interesting custom helpers. + public byte[] getArrayBuffer(int index) throws JSONException { + String encoded = baseArgs.getString(index); + return Base64.decode(encoded, Base64.DEFAULT); + } +} + + diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java new file mode 100644 index 0000000..081127d --- /dev/null +++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaBridge.java @@ -0,0 +1,183 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +package org.apache.cordova; + +import org.apache.cordova.PluginManager; +import org.json.JSONArray; +import org.json.JSONException; + +import android.util.Log; + +/** + * Contains APIs that the JS can call. All functions in here should also have + * an equivalent entry in CordovaChromeClient.java, and be added to + * cordova-js/lib/android/plugin/android/promptbasednativeapi.js + */ +public class CordovaBridge { + private static final String LOG_TAG = "CordovaBridge"; + private PluginManager pluginManager; + private NativeToJsMessageQueue jsMessageQueue; + private volatile int expectedBridgeSecret = -1; // written by UI thread, read by JS thread. + private String loadedUrl; + + public CordovaBridge(PluginManager pluginManager, NativeToJsMessageQueue jsMessageQueue) { + this.pluginManager = pluginManager; + this.jsMessageQueue = jsMessageQueue; + } + + public String jsExec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException { + if (!verifySecret("exec()", bridgeSecret)) { + return null; + } + // If the arguments weren't received, send a message back to JS. It will switch bridge modes and try again. See CB-2666. + // We send a message meant specifically for this case. It starts with "@" so no other message can be encoded into the same string. + if (arguments == null) { + return "@Null arguments."; + } + + jsMessageQueue.setPaused(true); + try { + // Tell the resourceApi what thread the JS is running on. + CordovaResourceApi.jsThread = Thread.currentThread(); + + pluginManager.exec(service, action, callbackId, arguments); + String ret = null; + if (!NativeToJsMessageQueue.DISABLE_EXEC_CHAINING) { + ret = jsMessageQueue.popAndEncode(false); + } + return ret; + } catch (Throwable e) { + e.printStackTrace(); + return ""; + } finally { + jsMessageQueue.setPaused(false); + } + } + + public void jsSetNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException { + if (!verifySecret("setNativeToJsBridgeMode()", bridgeSecret)) { + return; + } + jsMessageQueue.setBridgeMode(value); + } + + public String jsRetrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException { + if (!verifySecret("retrieveJsMessages()", bridgeSecret)) { + return null; + } + return jsMessageQueue.popAndEncode(fromOnlineEvent); + } + + private boolean verifySecret(String action, int bridgeSecret) throws IllegalAccessException { + if (!jsMessageQueue.isBridgeEnabled()) { + if (bridgeSecret == -1) { + Log.d(LOG_TAG, action + " call made before bridge was enabled."); + } else { + Log.d(LOG_TAG, "Ignoring " + action + " from previous page load."); + } + return false; + } + // Bridge secret wrong and bridge not due to it being from the previous page. + if (expectedBridgeSecret < 0 || bridgeSecret != expectedBridgeSecret) { + throw new IllegalAccessException(); + } + return true; + } + + /** Called on page transitions */ + void clearBridgeSecret() { + expectedBridgeSecret = -1; + } + + /** Called by cordova.js to initialize the bridge. */ + int generateBridgeSecret() { + expectedBridgeSecret = (int)(Math.random() * Integer.MAX_VALUE); + return expectedBridgeSecret; + } + + public void reset(String loadedUrl) { + jsMessageQueue.reset(); + clearBridgeSecret(); + this.loadedUrl = loadedUrl; + } + + public String promptOnJsPrompt(String origin, String message, String defaultValue) { + if (defaultValue != null && defaultValue.length() > 3 && defaultValue.startsWith("gap:")) { + JSONArray array; + try { + array = new JSONArray(defaultValue.substring(4)); + int bridgeSecret = array.getInt(0); + String service = array.getString(1); + String action = array.getString(2); + String callbackId = array.getString(3); + String r = jsExec(bridgeSecret, service, action, callbackId, message); + return r == null ? "" : r; + } catch (JSONException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return ""; + } + // Sets the native->JS bridge mode. + else if (defaultValue != null && defaultValue.startsWith("gap_bridge_mode:")) { + try { + int bridgeSecret = Integer.parseInt(defaultValue.substring(16)); + jsSetNativeToJsBridgeMode(bridgeSecret, Integer.parseInt(message)); + } catch (NumberFormatException e){ + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return ""; + } + // Polling for JavaScript messages + else if (defaultValue != null && defaultValue.startsWith("gap_poll:")) { + int bridgeSecret = Integer.parseInt(defaultValue.substring(9)); + try { + String r = jsRetrieveJsMessages(bridgeSecret, "1".equals(message)); + return r == null ? "" : r; + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return ""; + } + else if (defaultValue != null && defaultValue.startsWith("gap_init:")) { + // Protect against random iframes being able to talk through the bridge. + // Trust only file URLs and the start URL's domain. + // The extra origin.startsWith("http") is to protect against iframes with data: having "" as origin. + if (origin.startsWith("file:") || (origin.startsWith("http") && loadedUrl.startsWith(origin))) { + // Enable the bridge + int bridgeMode = Integer.parseInt(defaultValue.substring(9)); + jsMessageQueue.setBridgeMode(bridgeMode); + // Tell JS the bridge secret. + int secret = generateBridgeSecret(); + return ""+secret; + } else { + Log.e(LOG_TAG, "gap_init called from restricted origin: " + origin); + } + return ""; + } + return null; + } + + public NativeToJsMessageQueue getMessageQueue() { + return jsMessageQueue; + } +} diff --git a/platforms/android/CordovaLib/src/org/apache/cordova/CordovaChromeClient.java b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaChromeClient.java new file mode 100755 index 0000000..737d0b8 --- /dev/null +++ b/platforms/android/CordovaLib/src/org/apache/cordova/CordovaChromeClient.java @@ -0,0 +1,331 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +package org.apache.cordova; + +import org.apache.cordova.CordovaInterface; +import org.apache.cordova.LOG; + +import android.annotation.TargetApi; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.webkit.ConsoleMessage; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebStorage; +import android.webkit.WebView; +import android.webkit.GeolocationPermissions.Callback; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; + +/** + * This class is the WebChromeClient that implements callbacks for our web view. + * The kind of callbacks that happen here are on the chrome outside the document, + * such as onCreateWindow(), onConsoleMessage(), onProgressChanged(), etc. Related + * to but different than CordovaWebViewClient. + * + * @see WebChromeClient + * @see WebView guide + * @see CordovaWebViewClient + * @see CordovaWebView + */ +public class CordovaChromeClient extends WebChromeClient { + + public static final int FILECHOOSER_RESULTCODE = 5173; + private String TAG = "CordovaLog"; + private long MAX_QUOTA = 100 * 1024 * 1024; + protected CordovaInterface cordova; + protected CordovaWebView appView; + + // the video progress view + private View mVideoProgressView; + + // File Chooser + public ValueCallback mUploadMessage; + + @Deprecated + public CordovaChromeClient(CordovaInterface cordova) { + this.cordova = cordova; + } + + public CordovaChromeClient(CordovaInterface ctx, CordovaWebView app) { + this.cordova = ctx; + this.appView = app; + } + + @Deprecated + public void setWebView(CordovaWebView view) { + this.appView = view; + } + + /** + * Tell the client to display a javascript alert dialog. + * + * @param view + * @param url + * @param message + * @param result + * @see Other implementation in the Dialogs plugin. + */ + @Override + public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { + AlertDialog.Builder dlg = new AlertDialog.Builder(this.cordova.getActivity()); + dlg.setMessage(message); + dlg.setTitle("Alert"); + //Don't let alerts break the back button + dlg.setCancelable(true); + dlg.setPositiveButton(android.R.string.ok, + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + result.confirm(); + } + }); + dlg.setOnCancelListener( + new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + result.cancel(); + } + }); + dlg.setOnKeyListener(new DialogInterface.OnKeyListener() { + //DO NOTHING + public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) + { + result.confirm(); + return false; + } + else + return true; + } + }); + dlg.show(); + return true; + } + + /** + * Tell the client to display a confirm dialog to the user. + * + * @param view + * @param url + * @param message + * @param result + * @see Other implementation in the Dialogs plugin. + */ + @Override + public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { + AlertDialog.Builder dlg = new AlertDialog.Builder(this.cordova.getActivity()); + dlg.setMessage(message); + dlg.setTitle("Confirm"); + dlg.setCancelable(true); + dlg.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + result.confirm(); + } + }); + dlg.setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + result.cancel(); + } + }); + dlg.setOnCancelListener( + new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + result.cancel(); + } + }); + dlg.setOnKeyListener(new DialogInterface.OnKeyListener() { + //DO NOTHING + public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) + { + result.cancel(); + return false; + } + else + return true; + } + }); + dlg.show(); + return true; + } + + /** + * Tell the client to display a prompt dialog to the user. + * If the client returns true, WebView will assume that the client will + * handle the prompt dialog and call the appropriate JsPromptResult method. + * + * Since we are hacking prompts for our own purposes, we should not be using them for + * this purpose, perhaps we should hack console.log to do this instead! + * + * @see Other implementation in the Dialogs plugin. + */ + @Override + public boolean onJsPrompt(WebView view, String origin, String message, String defaultValue, JsPromptResult result) { + // Unlike the @JavascriptInterface bridge, this method is always called on the UI thread. + String handledRet = appView.bridge.promptOnJsPrompt(origin, message, defaultValue); + if (handledRet != null) { + result.confirm(handledRet); + } else { + // Returning false would also show a dialog, but the default one shows the origin (ugly). + final JsPromptResult res = result; + AlertDialog.Builder dlg = new AlertDialog.Builder(this.cordova.getActivity()); + dlg.setMessage(message); + final EditText input = new EditText(this.cordova.getActivity()); + if (defaultValue != null) { + input.setText(defaultValue); + } + dlg.setView(input); + dlg.setCancelable(false); + dlg.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + String usertext = input.getText().toString(); + res.confirm(usertext); + } + }); + dlg.setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + res.cancel(); + } + }); + dlg.show(); + } + return true; + } + + /** + * Handle database quota exceeded notification. + */ + @Override + public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, + long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) + { + LOG.d(TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota); + quotaUpdater.updateQuota(MAX_QUOTA); + } + + // console.log in api level 7: http://developer.android.com/guide/developing/debug-tasks.html + // Expect this to not compile in a future Android release! + @SuppressWarnings("deprecation") + @Override + public void onConsoleMessage(String message, int lineNumber, String sourceID) + { + //This is only for Android 2.1 + if(android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.ECLAIR_MR1) + { + LOG.d(TAG, "%s: Line %d : %s", sourceID, lineNumber, message); + super.onConsoleMessage(message, lineNumber, sourceID); + } + } + + @TargetApi(8) + @Override + public boolean onConsoleMessage(ConsoleMessage consoleMessage) + { + if (consoleMessage.message() != null) + LOG.d(TAG, "%s: Line %d : %s" , consoleMessage.sourceId() , consoleMessage.lineNumber(), consoleMessage.message()); + return super.onConsoleMessage(consoleMessage); + } + + @Override + /** + * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin. + * + * @param origin + * @param callback + */ + public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) { + super.onGeolocationPermissionsShowPrompt(origin, callback); + callback.invoke(origin, true, false); + } + + // API level 7 is required for this, see if we could lower this using something else + @Override + public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) { + this.appView.showCustomView(view, callback); + } + + @Override + public void onHideCustomView() { + this.appView.hideCustomView(); + } + + @Override + /** + * Ask the host application for a custom progress view to show while + * a