Giter VIP home page Giter VIP logo

klippa-app / nativescript-http Goto Github PK

View Code? Open in Web Editor NEW
33.0 2.0 15.0 4.05 MB

The best way to do HTTP requests in NativeScript, a drop-in replacement for the core HTTP with important improvements and additions like proper connection pooling, form data support and certificate pinning

License: MIT License

Shell 1.03% TypeScript 68.24% Java 18.17% JavaScript 3.66% CSS 0.17% HTML 1.49% Ruby 0.09% Vue 6.79% SCSS 0.37%
nativescript nativescript-plugin nativescript-angular http http-client http-requests tls ssl gzip http2

nativescript-http's Introduction

nativescript-http

NPM version Downloads TotalDownloads Build Status

πŸš€ The best way to do HTTP requests in NativeScript πŸš€

A drop-in replacement for the core HTTP with important improvements and additions like proper connection pooling, form data support and certificate pinning.

Features

  • Ability to use without any code change
  • Ability to make all http and image-cache requests go through this plugin
  • Backwards compatible (behaves the same as core HTTP)
  • Modern TLS & SSL security features
  • Shared connection pooling reduces request latency
  • Control over concurrency/connection pooling
  • Silently recovers from common connection problems
  • Everything runs on a native background thread
  • Transparent GZIP to shrink response size
  • HTTP/2 and SPDY support
  • Support for directly posting ArrayBuffer/File/Blob/native(such as java.io.File and NSData.dataWithContentsOfFile) objects in the content property
  • Multipart form data (multipart/form-data) support (for file uploads), supports ArrayBuffer, File, Blob and native objects (like java.io.File and NSData.dataWithContentsOfFile)
  • Ability to set a global user agent
  • Ability to control cookies
  • Ability to control background image parsing
  • Certificate/SSL pinning
  • WebSockets
  • ImageCache

NativeScript Version Support

NS Version nativescript-http version Install command Docs
^8.0.0 ^3.0.0 ns plugin add @klippa/nativescript-http@^3.0.0 This page
^7.0.0 ^2.0.0 ns plugin add @klippa/nativescript-http@^2.0.0 Here
^6.0.0 ^1.0.0 tns plugin add @klippa/nativescript-http@^1.0.0 Here

Installation (NS 8)

ns plugin add @klippa/nativescript-http@^3.0.0

Usage (NS 8)

Automatically use this plugin for all HTTP calls

Since this is a drop-in replacement for the core HTTP, we can automatically use this plugin for all HTTP calls in NativeScript that use the XHR framework to do HTTP calls, this includes:

  • Any JavaScript/Angular/Vue plugin that was created to be used in the browser
    • Axios
    • Angular HTTPClient
    • vue-resource
  • Any NativeScript http method
    • request
    • fetch
    • getString, getJSON, getImage, getFile, getBinary
  • NativeScript image-cache
  • Any NativeScript plugin that uses above methods internally

The way to do this is quite simple, we only have to import a plugin and add the plugin to the webpack config.

Open the file webpack.config.js, it may look like this:

const webpack = require("@nativescript/webpack");

module.exports = (env) => {
   webpack.init(env);

   // Learn how to customize:
   // https://docs.nativescript.org/webpack

   return webpack.resolveConfig();
};

Import our webpack implementation and add a line before webpack.resolveConfig(), like this:

const webpack = require("@nativescript/webpack");
const NativeScriptHTTPPlugin = require("@klippa/nativescript-http/webpack"); // Import NativeScriptHTTPPlugin

module.exports = (env) => {
   webpack.init(env);

   // Learn how to customize:
   // https://docs.nativescript.org/webpack

   webpack.chainWebpack(config => {
      config.plugin('NativeScriptHTTPPlugin').use(NativeScriptHTTPPlugin)
   });

   return webpack.resolveConfig();
};

The NativeScriptHTTPPlugin can be given an object with the following properties: replaceHTTP (true/false) and replaceImageCache (true/false). This way you can control what the plugin replaces. If you don't give this options object we will replace both. The options can be passed like this:

webpack.chainWebpack(config => {
   config.plugin('NativeScriptHTTPPlugin').use(NativeScriptHTTPPlugin, [
      {
         replaceHTTP: true,
         replaceImageCache: false
      }
   ])
});

Note: if you do this, you don't have to do the other integrations.

Validate whether the automatic integration works by adding a self-check

If you are dependant on new functionality in this plugin, like handling form data or certificate pinning and you want to make sure the automatic integration always works, or you just want to play it safe, you can add the following self-check to your code:

For core NativeScript / Vue / Angular:

import { Http, Dialogs } from "@nativescript/core";

Http.request({
    method: "GET",
    url: "https://nativescript-http-integration-check.local",
}).then((res) => {
    const jsonContent = res.content.toJSON();
    if (!jsonContent || !jsonContent.SelfCheck || jsonContent.SelfCheck !== "OK!") {
        Dialogs.alert("nativescript-http automatic integration failed! Request to https://nativescript-http-integration-check.local failed");
    }
}).catch((e) => {
    Dialogs.alert("nativescript-http automatic integration failed! Request to https://nativescript-http-integration-check.local failed");
});

For Angular HttpClient:

import { Dialogs } from "@nativescript/core";

// Don't forget to inject HttpClient into your component.

// Add the following code in a place where you want to do the self-check in Angular.
this.http.get("https://nativescript-http-integration-check.local", {
    responseType: "json",
}).toPromise().then((res) => {
    // @ts-ignore
    if (!res || !res.SelfCheck || res.SelfCheck !== "OK!") {
        Dialogs.alert("nativescript-http automatic integration failed! Request to https://nativescript-http-integration-check.local failed");
    }
}).catch((e) => {
    Dialogs.alert("nativescript-http automatic integration failed! Request to https://nativescript-http-integration-check.local failed");
});

The URL https://nativescript-http-integration-check.local is hardcoded internally in this plugin to always return the same result.

If the request fails, or the content isn't the same as what we expect, we know something is wrong and we will get a dialog message that the automatic integration failed.

Integration in code

Since this is a drop-in replacement for the core HTTP, you can execute the requests in the same way as with the Core HTTP, the only thing different is the import:

The format of options and the output of the request are the same as in core HTTP.

import { HttpResponse } from "@nativescript/core";
import { Http } from "@klippa/nativescript-http";

Http.request({
   url: "https://httpbin.org/get",
   method: "GET"
}).then((response: HttpResponse) => {
   // Argument (response) is HttpResponse
}, (e) => {
});

Integration in Angular

We also provide a drop-in replacement NativeScriptHttpClientModule from the nativescript-angular project.

In order to make Angular use our HTTP implementation, import our module like this:

import { NativeScriptHttpClientModule } from "@klippa/nativescript-http/angular";

@NgModule({
    imports: [
        NativeScriptHttpClientModule
    ]

From now on you can make requests using Angular's HttpClient service like explained here.

Be aware that this plugin tries to parse your image in the background so you won't have to do this in javascript (core HTTP does the same). This value is not reachable from the Angular HTTP client, only through response.content.toImage(), so I would advice to use the HTTP client directly (so without the Angular HTTP client) if you are going to download images and display them directly.

ImageCache

If you use the WebPack plugin, you don't have to do anything to use our ImageCache. It behaves the same as core so you don't have to change anything.

If you don't use the plugin. You can import the ImageCache class from @klippa/nativescript-http. It has the same API as the core ImageCache.

Important note for apps with support for < Android 5 (SDK 21)

The default minSdk of NativeScript is 17, this is Android 4.2. We use OkHttp version 4, which does not have support for Android 4.

If you do not care about Android 4 users

If you do not care about Android 4 users, edit the file App_Resources/Android/app.gradle and change the minSdk to 21:

android {
  defaultConfig {
    minSdkVersion 21
    // ... other config.
  }
  // ... other config.
}

This let's the play store know the app can't be installed on anything lower than Android 5.

If you do care about Android 4 users

Luckily, OkHtpp has a special support branch called okhttp_3.12.x for older Android version, and because OkHttp is binary safe, which means all the methods have the same signature, we can just replace the version and everything just worksβ„’.

I don't mind using an older OkHttp version

If you don't mind everyone having an older OkHttp version, you can do the following easyβ„’ fix:

Edit the file App_Resources/Android/app.gradle, add the following lines:

android {
  // ... other config.
  configurations.all {
    resolutionStrategy.force "com.squareup.okhttp3:okhttp:3.12.+"
  }
}

This will force your build to use the support version of OkHttp.

Please note that this okhttp_3.12.x branch is support through December 31, 2020, and it will only get fixes for severe bugs or security issues.

This means you won't get any cool features from version 4.

I want to use the latest version for Android 5, and version 3.12 for Android 4

NOTE: there is currently an open issue in the Android runtime that makes it impossible for the configuration below to work

Luckily, this is also a possibility, but a little bit more difficult because you have to split your builds.

Edit the file App_Resources/Android/app.gradle, add the following lines:

android {
  // ... other config.
  flavorDimensions "api"

  productFlavors {
    minApi21 {
      dimension "api"
      minSdkVersion 21
      versionNameSuffix "-minApi21"
    }

    minApi17 {
      dimension "api"
      minSdkVersion 17
      versionNameSuffix "-minApi17"
    }
  }
}

android.applicationVariants.all { variant ->
  if (variant.name.contains("minApi17")) {
    variant.getCompileConfiguration().resolutionStrategy.force "com.squareup.okhttp3:okhttp:3.12.+"
    variant.getRuntimeConfiguration().resolutionStrategy.force "com.squareup.okhttp3:okhttp:3.12.+"
  }

  variant.outputs.each { output ->
    if (variant.name.contains("minApi17")) {
      output.versionCodeOverride = 10000000 + variant.versionCode
    } else {
      output.versionCodeOverride = 20000000 + variant.versionCode
    }
  }
}

The part in android is to create 2 product flavors, one for minSdk 17, and one for minSdk 21.

The part in android.applicationVariants consists of two things:

  1. Making sure flavor minApi17 uses version 3.12.+ for minSdk 17
  2. Making sure that every flavor has it's own build versionCode. It takes the version from the manifest and does (10000000 + manifestVersionCode) for minApi17 and (20000000 + manifestVersionCode) for minApi21.

This will create 2 APK's when you build a release, one for Android 4 (app-minApi17-release.apk), and one for Android 5 (app-minApi21-release.apk). You can also combine this with ABI splitting.

When you upload both APK's to the Playstore, Google will make sure the proper APK get's distributed to the different devices.

Comparison with other NativeScript HTTP Clients

Plugin Android iOS Background threads Supports form data Proper connection pooling Can replace core http Certificate / SSL Pinning WebSockets ImageCache
@nativescript/core/http βœ”οΈ using Java HttpURLConnection βœ”οΈ using NSURLSession βœ”οΈ ❌ ❌ bad Android implementation - ❌ ❌ -
nativescript-background-http βœ”οΈ using gotev/android-upload-service βœ”οΈ using NSURLSession βœ”οΈ (with a service) ❌ Unknown ❌ ❌ ❌ ❌
nativescript-http-formdata βœ”οΈ using OkHttp4 βœ”οΈ using OMGHTTPURLRQ ❌ βœ”οΈ ❌ bad OkHttp implementation ❌ ❌ ❌ ❌
nativescript-okhttp βœ”οΈ using OkHttp2 ❌ ❌ ❌ ❌ bad OkHttp implementation ❌ ❌ ❌ ❌
nativescript-https βœ”οΈ using OkHttp3 βœ”οΈ using AFNetworking βœ”οΈ ❌ βœ”οΈ shared client βœ… by manually replacing calls, data structures are (almost) the same βœ”οΈ ❌ ❌
@klippa/nativescript-http βœ”οΈ using OkHttp4 βœ”οΈ using NSURLSession βœ”οΈ βœ”οΈ βœ”οΈ shared client βœ”οΈ automatically and manually βœ”οΈ βœ”οΈ βœ”οΈ

Implementation differences with NativeScript Core HTTP

  • We only try to parse the response as Image when the Content-Type starts with image/
  • We use a default timeout of 60s for connect/write/read, you can change this using the timeout option
  • While the code of Core HTTP looks like it supports FormData, it only supports key/value and not files, we do support it with our HTTPFormData class.

API

Form data

By default this client behaves the same as the Core HTTP for FormData objects, meaning it will just encode it as key=value pairs and it does not support Blob/File objects. It will be posted as application/x-www-form-urlencoded unless you override it using a custom header.

If you want to create multipart form data (multipart/form-data) requests, you can use the HTTPFormData class from this plugin. You can create form data requests like this:

import { HttpResponse } from "@nativescript/core";
import { Http, HTTPFormData, HTTPFormDataEntry } from "@klippa/nativescript-http";

const form = new HTTPFormData();
form.append("value", "Test");
// You can also append ArrayBuffer/File/Blob/native(such as java.io.File and NSData.dataWithContentsOfFile) objects directly to form here, but please keep in mind that only the File object has the ability to set a filename. And only Blob/File objects have the ability to set a content type.
// Use HTTPFormDataEntry if you want more control.

// formFile data can be a JavaScript ArrayBuffer but also native file objects like java.io.File and NSData.dataWithContentsOfFile.
const formFile = new HTTPFormDataEntry(new java.io.File(fileLocation), "test.png", "image/png");
form.append("file", formFile);

Http.request({
    url: "https://httpbin.org/post",
    method: "POST",
    content: form
}).then((response: HttpResponse) => {
    // Argument (response) is HttpResponse
}, (e) => {
});

Note: this does not work with the Angular HTTPClient, because it tries to transform the HTTPFormData to json. Use the request() method for Multipart posting.

Controlling image decode (Android only)

The NativeScript HTTP implementation always tries to decode responses as image to make sure toImage() works fast. However, a lot of times you don't want it to do this, as you are not expecting images. By default this plugin only works like this when the endpoint returns a proper image content type (ImageParseMethod.CONTENTTYPE). With this method you can control this behaviour, with ImageParseMethod.ALWAYS you revert to Core HTTP behaviour, with ImageParseMethod.NEVER you can completely disable it.

Note: only has affect on Android, on iOS image decoding already only happens when you use toImage().

import { setImageParseMethod, ImageParseMethod } from "@klippa/nativescript-http";

// Add this line where you want to change the image parse mode.
// Options are: NEVER/CONTENTTYPE/ALWAYS.
setImageParseMethod(ImageParseMethod.ALWAYS);

Controlling cookies

Clear all cookies:

import { clearCookies } from "@klippa/nativescript-http";

// Add this line where you want to clear cookies.
clearCookies();

Controlling concurrency / connection pool limits

Note: only the domain limit has effect on iOS.

import { setConcurrencyLimits } from "@klippa/nativescript-http";

// Add this line where you want to set the concurrency limits.
// First argument is total limit, second per domain.
setConcurrencyLimits(20, 5);

Setting a global User Agent

import { setUserAgent } from "@klippa/nativescript-http";

// Add this line where you want to set the user agent.
setUserAgent("MyCoolApp");

WebSockets

Note: certificate pinning is not available for websockets on iOS. Sadly SocketRocket removed support for that.

Creating a WebSocket is quite simple in this plugin:

import { newWebsocketConnection } from "@klippa/nativescript-http/websocket";

newWebsocketConnection({
    url: "wss://echo.websocket.org",
    method: "GET",
}, {
    // It's important to wrap callbacks in ngZone for Angular when you do anything binding related.
    // If you don't do this, Angular won't update the views.
    onClosed: (code: number, reason: string) => {
        // Invoked when both peers have indicated that no more messages will be transmitted and the connection has been successfully released.
        // No further calls to this callback will be made.
        console.log("onClosed", code, reason);
    },
    onFailure: (error) => {
        // Invoked when a web socket has been closed due to an error reading from or writing to the network.
        // Both outgoing and incoming messages may have been lost. No further calls to this callback will be made.
        console.log("onFailure", error);
    },
    onOpen: () => {
        // Invoked when a web socket has been accepted by the remote peer and may begin transmitting messages.
        console.log("onOpen");
    },
    onClosing: (code: number, reason: string) => {
        // Invoked when the remote peer has indicated that no more incoming messages will be transmitted.
        // This method will not be called on iOS.
        console.log("onClosing", code, reason);
    },
    onMessage: (text: string) => {
        // Invoked when a text (type 0x1) message has been received.
        console.log("onMessage", text);
    },
    onBinaryMessage: (data: ArrayBuffer) => {
        // Invoked when a binary (type 0x2) message has been received.
        console.log("onBinaryMessage", data);
    }
}).then((webSocket) => {
    // With the webSocket object you can send messages and close the connection.
    // Receiving a WebSocket here does not mean the connection worked, you have to check onFailure and onOpen for that.
});

Certificate pinning

Please read about certificate pinning before you enable it. It can have serious consequences. Good articles are here and here.

You can use this question on Stack Overflow to learn how to get the certificate hashes.

Always provide at least one backup pin

In order to prevent accidentally locking users out of your app, make sure you have at least one backup pin and that you have procedures in place to transition to using the backup pin if your primary pin can no longer be used. For example, if you pin to the public key of your server's certificate, you should generate a backup key that is stored somewhere safe. If you pin to an intermediate CA or a root CA, then you should also select an alternative CA that you are willing to switch to if your current CA (or their intermediate CA) becomes invalid for some reason.

If you do not have a backup pin, you could inadvertently prevent your app from working until you released a new version of your app, and your users updated it. One such incident led to a bank having to ask their CA to issue a new certificate using a deprecated intermediate CA in order to allow their users to use the app, or face weeks of the app being unusable.

import { certificatePinningAdd, certificatePinningClear } from "@klippa/nativescript-http";

// Add this line where you want to pin the certificate to a specific domain. The second argument are the certificate hashes that you want to pin.
// You can use *.mydomain.com to also use this for direct subdomains, and **.mydomain.com for any subdomain.
// Note: for iOS, *.publicobject.com also behaves as **.publicobject.com due to limitation in TrustKit.
// Note 2: for Android, if you use the older version of OkHttp, the **. prefix does not work.
// Note 3: for iOS, you need to have at least 2 hashes, because Trustkit requires you to have a backup certificate.
certificatePinningAdd("mydomain.com", ["DCU5TkA8n3L8+QM7dyTjfRlxWibigF+1cxMzRhlJV4=", "Lh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=", "Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys="]);

// Use this to clear all certificate pins.
certificatePinningClear();

Roadmap

  • Cache control
  • Allowing self signed certificates (WIP in feature/self-signed)

About Klippa

Klippa is a scale-up from Groningen, The Netherlands and was founded in 2015 by six Dutch IT specialists with the goal to digitize paper processes with modern technologies.

We help clients enhance the effectiveness of their organization by using machine learning and OCR. Since 2015 more than a 1000 happy clients have been served with a variety of the software solutions that Klippa offers. Our passion is to help our clients to digitize paper processes by using smart apps, accounts payable software and data extraction by using OCR.

License

The MIT License (MIT)

nativescript-http's People

Contributors

dependabot[bot] avatar edusperoni avatar jerbob92 avatar mayerlench avatar mukaschultze avatar triniwiz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

nativescript-http's Issues

Request hangs when using a Self-Signed certificate

NativeScript: 8.3.3
Android: v13 on Pixel 7

I have been using a self signed cert on Android for development successfully by a using a void trust manager. Setting HttpsURLConnection.setDefaultSSLSocketFactory seems to work with the core Http library.

When I switch over to @klippa/nativescript-http all requests hang indefinitely when making requests to the development server that uses a self signed certificate. I switch it back to the production server and everything works as expected.

Is there a way to set sslSocketFactory to a void trust manager on the OKHttp builder from within Javascript or is the only option to fork this repo and patch it for my own use case?

Feature request: Certificate transparency for Android

As I understand it (absolutely could be wrong),

  1. Certificate pinning is on the outs, with Android explicitly recommending against it.
  2. Certificate transparency is a useful alternative to pinning.
  3. iOS supports certificate transparency by default, but Android does not. ( Noted halfway down this article from 2020 )
  4. This package supports everything http-related except for certificate transparency.

Assuming the above is correct, would it make sense for this package to support certificate transparency(CT), since CT seems to essentially be a replacement for pinning?

Why not suggest a custom webpack configuration?

According to the docs, one should be able to just do this:

// my-custom.webpack.config.js
const webpackConfig = require("./webpack.config");
const NativeScriptHTTPPlugin = require("@klippa/nativescript-http/webpack");

module.exports = (env) => {
  const config = webpackConfig(env);
  config.plugins.push(new NativeScriptHTTPPlugin());
  return config;
};

And in nativescript.config.ts, set webpackConfigPath to "./my-custom.webpack.config.js"

No more hassling with the stock webpack config anymore.

[IOS] - Clear Cookies

Hi,

I've a problem with method "clearCookies" on iOS if executed from the second time.
I've this error:
Error: *** __boundsFail: index 3 beyond bounds [0 .. 1]

I had to use a try/catch to intercept the error.

Do you know how to fix?

Thanks

[Question] Webpack 5 Error

Which platform(s) does your issue occur on?

  • Both

Please, provide the following version numbers that your issue occurs with:

  • CLI: 8.0.1
  • Cross-platform modules: 8.0.0
  • Runtime(s): 8.0.0

I am trying to use this in a NS8 Project and am getting the following error on the logs when trying to run the application

ERROR in NormalModuleFactory.beforeResolve (NativeScriptHTTPPlugin, angular-compiler) is no longer a waterfall hook, but a bailing hook instead. Do not return the passed object, but modify it instead. Returning false will ignore the request and results in no module created.

I am implementing the plugin in the web pack using the documentation,

webpack.chainWebpack(config => {
    config.plugin('NativeScriptHTTPPlugin').use(NativeScriptHTTPPlugin);
});

Does this not support NS8 Webpack yet? I will try to implement this by importing the HTTP Module for now.

how to read cookies

how can the cookie jars be read after an http call was responded with "set-cookie" header. please keep in mind that the actual http response was a redirect, so that just reading the headers from the response is not possible, as the set-cookie header is already gone. this is the reason why i need to read the cookie jar.

Keep uploading images in background on iOS

I'm using your plugin to upload images to a server, and I was wondering if there is a way to keep uploading images in the background on iOS, after an app is minimized?

Now the upload stops instantly when minimizing the app.

[Review Request] Roadmap Step - Cache Control

Hi @jerbob92 ,

I tried implementing cache control in the plugin and it works partially. For iOS I was able to directly set Cache Policy as urlRequest.cachePolicy = NSURLRequestCachePolicy.UseProtocolCachePolicy; or whatever.

But for Android I noticed that you are making the request with the AAR created by you and not directly with okhttp3.

I thought of rewriting the request function for android of the plugin with OkHttp. However before I start that, I thought of getting in touch with you for a possibility to add cache control parameter to com.klippa.NativeScriptHTTP.Async.Http.MakeRequest(requestOptions, callbackComplete, requestId)

Currently there are 3 parameters in MakeRequest

RequestOptions
CallbackComplete
Request Id Counter

We can add in a fourth Parameter CacheControlPolicy which will be added to the okhttp request.

You must be building a request of okHttp inside the MakeRequest function similar to var request = new okhttp3.Request.Builder(); we can just add the cache control builder to that request to make it work request.cacheControl(cacheControlPolicy);

I have committed my changes to the forked repository here.

Please have a look at the request function in http.ios.ts and http.android.ts and let me know.

[ANDROID] - Fatal Exception: java.util.ConcurrentModificationException

On my app I've this crash on Crashlytics:

Fatal Exception: java.util.ConcurrentModificationException
       at java.util.HashMap$HashIterator.nextNode(HashMap.java:1441)
       at java.util.HashMap$KeyIterator.next(HashMap.java:1465)
       at com.klippa.NativeScriptHTTP.SetCookieCache$SetCookieCacheIterator.next(SetCookieCache.java:51)
       at com.klippa.NativeScriptHTTP.SetCookieCache$SetCookieCacheIterator.next(SetCookieCache.java:36)
       at com.klippa.NativeScriptHTTP.MemoryCookieJar.loadForRequest(MemoryCookieJar.java:29)
       at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:74)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
       at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:74)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
       at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:197)
       at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:502)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
       at java.lang.Thread.run(Thread.java:764)

Maybe is not thread safe? How to prevent to crash?

Which platform(s) does your issue occur on?

Android

Please, provide the following version numbers that your issue occurs with:

  • CLI: 6.7.4
  • Cross-platform modules: (check the 'version' attribute in the
    6.5.4
  • Runtime(s): 6.5.0
  • Plugin(s):
    @klippa/nativescript-http: 1.3.1

Unexpected end of JSON input

When i do

let res = await Http.request({
                    url:"xxxxx",
                        method: "DELETE,
                        headers: {
                          Authorization: "Bearer XXXX"
                       }
               });
console.log("res",res);

and the server responds with an empty body (which is valid for DELETE) and status 204. then i get the above error. it seems this library tries to parse the body no matter what.

Which platform(s) does your issue occur on?

  • Android 11

Access to native error / request error type to differentiate network errors

Hello, I might have missed something, but it doesn't seem possible to retrieve the original / native errors thrown on iOS and Android by their respective networking libraries in order to determine whether the error is a network error, a timeout error or another kind of error.

Is there a way to get this information ? Or an easy way around the fact that errors returned by the @klippa/nativescript-http plugin are strings ?

For my use case, I managed to naively parse the returned strings and deduce the error but it turns out the iOS implementation returns an Error(error.localizedDescription) so parsing won't work in that case :)

Any tip would be much appreciated.

Thanks, great plugin otherwise !

NS8 Webpack path replacement module does not take into account Windows 10 backslashes

... therefore for Windows 10 users the webpack module will always fail.

// ..\@klippa\nativescript-http\webpack\index.js
apply(compiler) {
        const resourceRegExp = /http-request|image-cache/;
        compiler.hooks.normalModuleFactory.tap(
            "NativeScriptHTTPPlugin",
            nmf => {
                nmf.hooks.beforeResolve.tap("NativeScriptHTTPPlugin", result => {
                    if (!result) return;

                    // Replace http-request imports by our own.
                    if (resourceRegExp.test(result.request)) {
                        // Replace the relative http-request import from core http.
                        if (this.replaceHTTP && result.request === "./http-request") {
                            console.log("[@klippa\nativescript-http\webpack\index.js]", result.context, result.context.endsWith("@nativescript/core/http"), result.context.endsWith("@nativescript\\core\\http")); 
                            // Result: [@klippa\nativescript-http\webpack\index.js] D:\Folder1\Folder2\node_modules\@nativescript\core\http false true

                            if (result.context.endsWith("@nativescript/core/http")) {
                                result.request = "../../../@klippa/nativescript-http";
                            }
                            if (result.context.endsWith("tns-core-modules/http")) {
                                result.request = "../../@klippa/nativescript-http";
                            }
                        }

                        // Replace the relative http-request import from core image-cache (for iOS).
                        if (this.replaceHTTP && result.request === "../../http/http-request") {
                            if (result.context.endsWith("@nativescript/core/ui/image-cache")) {
                                result.request = "../../../../@klippa/nativescript-http";
                            }
                            if (result.context.endsWith("tns-core-modules/ui/image-cache")) {
                                result.request = "../../../@klippa/nativescript-http";
                            }
                        }

                        // Replace the relative image-cache import from core ui.
                        if (this.replaceImageCache && result.request === "./image-cache") {
                            if (result.context.endsWith("@nativescript/core/ui")) {
                                result.request = "../../../@klippa/nativescript-http/image-cache";
                            }
                            if (result.context.endsWith("tns-core-modules/ui")) {
                                result.request = "../../@klippa/nativescript-http/image-cache";
                            }
                        }

                        // When other code directly imports http-request.
                        if (this.replaceHTTP && (result.request === "@nativescript/core/http/http-request" || result.request === "tns-core-modules/http/http-request")) {
                            result.request = "@klippa/nativescript-http";
                        }

                        // When other code directly imports image-cache.
                        if (this.replaceImageCache && (result.request === "@nativescript/core/ui/image-cache" || result.request === "tns-core-modules/image-cache")) {
                            // Make sure we don't ruin our own import.
                            // We import image-cache for iOS because that implementation is fine.
                            if (!result.context.endsWith("src/image-cache") && !(result.context.endsWith("@klippa/nativescript-http/image-cache"))) {
                                result.request = "@klippa/nativescript-http/image-cache";
                            }
                        }
                    }
                    return;
                });
            }
        );
    }

Solution should be obvious.

EDIT:

In addition, I encountered an issue where the built-in "parseJSON" function got triggered when serializing console.log output of an object and the response content was an empty string, so it crashed the app. I realize the problem is not inside the 'parseJSON' itself, but in the way nativescript console.log works? Regardless, I think an empty passed string input to 'parseJSON' should return an empty string instead of continuing to call JSON.parse("").

P.S ... was too lazy to open a new issue, so mentioned it here.

Update OkHttp 4.10 -> 4.12

Hi! πŸ‘‹

Discovered an issue where requests in Android fail with a okhttp3.internal.http2.StreamResetException: stream was reset: INTERNAL_ERROR

Now, this is mentioned here as a server side issue - however in my case (and some of other people), the error did not occur on normal browsers nor in Postman etc.

Using a later version of OkHTTP seems to have solved this however!

Smallest diff ever below:

diff --git a/node_modules/@klippa/nativescript-http/platforms/android/include.gradle b/node_modules/@klippa/nativescript-http/platforms/android/include.gradle
index f94d213..9fffe42 100644
--- a/node_modules/@klippa/nativescript-http/platforms/android/include.gradle
+++ b/node_modules/@klippa/nativescript-http/platforms/android/include.gradle
@@ -5,5 +5,5 @@ android {
 }
 
 dependencies {
-    implementation "com.squareup.okhttp3:okhttp:4.10.+"
+    implementation "com.squareup.okhttp3:okhttp:4.12.+"
 }

This issue body was partially generated by patch-package.

ReferenceError: Cannot access 'Cache' before initialization

UPDATE
I tested this issue on a MAC/Android and it works, i dont get the error. The issue appears only on Windows

When I use the plugin in the webpack.config.js I get an error.
I can only get it to work if I pass the "replaceImageCache: false" config but then I don't get ImageCache

Nativescript 8
Flavor: react-nativescript
Windows/Android

const webpack = require("@nativescript/webpack");
const NativeScriptHTTPPlugin = require("@klippa/nativescript-http/webpack");


module.exports = (env) => {
	webpack.init(env);

	// Learn how to customize:
	// https://docs.nativescript.org/webpack
	webpack.chainWebpack(config => {

		config.plugin('NativeScriptHTTPPlugin').use(NativeScriptHTTPPlugin)

	});

	return webpack.resolveConfig();
};
// loading image in useEffect causes the error
    React.useEffect(() => {
        Http.getImage('https://cdn.britannica.com/60/217660-050-DBCC409A/cheddar-cheese-wedge.jpg')
            .then(async res => {
                const b64 = res.toBase64String('jpg', 1)
                console.log('πŸš€ ~ file: HomeScreen.tsx ~ line 16 ~ React.useEffect ~ b64', b64)
            })

    }, [])
System.err: ReferenceError: Cannot access 'Cache' before initialization
System.err:     at com.tns.Runtime.runModule(Native Method)
System.err:     at com.tns.Runtime.runModule(Runtime.java:689)
System.err:     at com.tns.Runtime.run(Runtime.java:681)
System.err:     at com.tns.NativeScriptApplication.onCreate(NativeScriptApplication.java:21)
System.err:     at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1192)
System.err:     at android.app.ActivityThread.handleMakeApplication(ActivityThread.java:7507)
System.err:     ... 9 more
Successfully synced application org.finitydevs.global on device R58M84FQC8N.

Cannot find runtime for instance=com.tns.gen.okhttp3.Callback

Hello,

We run an Android TV app that is designed to be running for days. Unfortunately at least once a day we're seeing the following crash. It's reported on MS App Center but I can never get it locally.

com.tns.NativeScriptException: Cannot find runtime for instance=com.tns.gen.okhttp3.Callback

com.tns.Runtime.callJSMethod Runtime.java:1157
com.tns.Runtime.callJSMethod Runtime.java:1138
com.tns.Runtime.callJSMethod Runtime.java:1134
com.tns.gen.okhttp3.Callback.onResponse Callback.java:26
okhttp3.RealCall$AsyncCall.execute RealCall.java:174
okhttp3.internal.NamedRunnable.run NamedRunnable.java:32
java.util.concurrent.ThreadPoolExecutor.runWorker ThreadPoolExecutor.java:1167

This usually happens after at least 5 hours running, sometimes days running.

Any ideas?

Thanks,
Liam

Public key pinning...backup keys

I'm working on public key pinning for my nativescript app and I came across this wonderful repo. Its pretty difficult to find straightforward information on public-key pinning and good instructions on how to do it

A few questions I have which maybe you can answer

For example, if you pin to the public key of your server's certificate, you should generate a backup key that is stored somewhere safe

  1. What type of key should be generated as a backup, another private key?
  2. How does this help user lockout from the app? is it because the private key doesnt change any of the SubjectPublicKeyInfo in the SSL certificate?

We currently have an API with certificates that change every 90 days from the same CA(lets encrypt). We don't want to have to release a new app every 90 days which will most likely cause user lockout.

We are trying to avoid this issue by pinning the public key but im failing to understand the backup keys process

N official integration

We just discovered your plugin and it is pretty awesome!
Could become an official N plugin (as moving to @NativeScript npm scope) if you are interested.

I think we could make it even better though:

Let us know what you think about that opportunity

Support for HTTP/3?

Any possibility of providing support for the new HTTP/3 spec?
There seem to be some native implementations already available.
Maybe something to have on the horizon.

Does This Support Binary File Upload (Image) in Formdata Submit

Make sure to check the demo app(s) for sample usage

Make sure to check the existing issues in this repository

If the demo apps cannot help and there is no issue for your problem, tell us about it

Please, ensure your title is less than 63 characters long and starts with a capital
letter.

Which platform(s) does your issue occur on?

  • Android 10
  • Device (Huawei Mate)

Please, provide the following version numbers that your issue occurs with:

TNS Version: 7.0.11

My package.json

"dependencies": {
"@angular/animations": "~10.1.0",
"@angular/common": "~10.1.0",
"@angular/compiler": "~10.1.0",
"@angular/core": "~10.1.0",
"@angular/forms": "~10.1.0",
"@angular/platform-browser": "~10.1.0",
"@angular/platform-browser-dynamic": "~10.1.0",
"@angular/router": "~10.1.0",
"@klippa/nativescript-http": "^2.0.1",
"@nativescript/angular": "~10.1.0",
"@nativescript/core": "~7.0.0",
"@nativescript/theme": "~2.3.0",
"@nstudio/nativescript-cardview": "^2.0.1",
"@nstudio/nativescript-floatingactionbutton": "^3.0.4",
"nativescript-carousel": "^7.0.1",
"nativescript-http-formdata": "^2.1.0",
"nativescript-imagepicker": "^7.1.0",
"nativescript-oauth2": "^3.0.2",
"nativescript-ui-calendar": "^7.0.2",
"nativescript-ui-chart": "^8.0.2",
"nativescript-ui-dataform": "^7.0.4",
"nativescript-ui-listview": "^9.0.4",
"nativescript-ui-sidedrawer": "~9.0.0",
"reflect-metadata": "~0.1.12",
"rxjs": "^6.6.0",
"zone.js": "~0.11.1"
},
"devDependencies": {
"@angular/cli": "^10.2.0",
"@angular/compiler-cli": "~10.1.0",
"@nativescript/android": "7.0.1",
"@nativescript/schematics": "^10.1.0",
"@nativescript/webpack": "~3.0.0",
"@ngtools/webpack": "~10.1.0",
"@schematics/angular": "^11.0.1",
"codelyzer": "~6.0.0",
"node-sass": "^4.14.1",
"tslint": "~6.1.3",
"typescript": "~4.0.3"
},

Is there any code involved?

My use case is very simple. Submit the image as binary file like when uploading image in web (I don't if this is supported already) in formdata.

So I already grab the image with no luck I cannot find enough resources to upload the image to my server as binary like the image below. I tried converting it to base64 format and I don't know if this is the right way to convert it to binary.

Capture

Here is my sample snippet when grabbing the image. I'm using nativescript-imagepicker.

let bitmapImage: any = image;
let stream = new java.io.ByteArrayOutputStream();
bitmapImage.compress(android.graphics.Bitmap.CompressFormat.PNG, 100, stream);
let byteArray = stream.toByteArray();
bitmapImage.recycle()
let image_data = byteArray;

Any help would be appreciated which would point my mistakes here. Thanks in advance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.