From aed6dc258a3149223a371b3df3a4f70e5f64d553 Mon Sep 17 00:00:00 2001 From: Andrii Chernenko Date: Wed, 11 Apr 2018 21:08:06 +0200 Subject: [PATCH 01/10] Remove obsolete code from RNHttpServerReactPackage.java --- .../com/strainy/RNHttpServer/RNHttpServerReactPackage.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/android/src/main/java/com/strainy/RNHttpServer/RNHttpServerReactPackage.java b/android/src/main/java/com/strainy/RNHttpServer/RNHttpServerReactPackage.java index 5258d37..f9602cd 100644 --- a/android/src/main/java/com/strainy/RNHttpServer/RNHttpServerReactPackage.java +++ b/android/src/main/java/com/strainy/RNHttpServer/RNHttpServerReactPackage.java @@ -24,11 +24,6 @@ public List createNativeModules( return modules; } - @Override - public List> createJSModules() { - return Collections.emptyList(); - } - @Override public List createViewManagers( ReactApplicationContext reactContext) { From 0f30868e65db319d7489af49a447a49d36bf0989 Mon Sep 17 00:00:00 2001 From: Andrii Chernenko Date: Wed, 11 Apr 2018 21:45:50 +0200 Subject: [PATCH 02/10] Roll back Server.java to version 0.1.2 --- .../src/main/java/com/strainy/RNHttpServer/Server.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/strainy/RNHttpServer/Server.java b/android/src/main/java/com/strainy/RNHttpServer/Server.java index 011470e..9d7eb47 100644 --- a/android/src/main/java/com/strainy/RNHttpServer/Server.java +++ b/android/src/main/java/com/strainy/RNHttpServer/Server.java @@ -114,7 +114,7 @@ public Response serve(IHTTPSession session) { response.getString("data") ); // Add headers to the response - ReadableMap rnHeaders = response.getMap("headers"); + /*ReadableMap rnHeaders = response.getMap("headers"); com.facebook.react.bridge.ReadableMapKeySetIterator iterator = rnHeaders.keySetIterator(); if (!iterator.hasNextKey()) { return null; @@ -123,7 +123,12 @@ public Response serve(IHTTPSession session) { String key = iterator.nextKey(); Log.d(TAG, key + "=" + rnHeaders.getString(key)); res.addHeader(key, rnHeaders.getString(key)); - } + }*/ + res.addHeader("Access-Control-Allow-Origin", "*"); + res.addHeader("Access-Control-Max-Age", "3628800"); + res.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); + res.addHeader("Access-Control-Allow-Headers", "X-Requested-With"); + res.addHeader("Access-Control-Allow-Headers", "Authorization"); return res; From 7937fde8d1b60db378a60b18121c6d1a835dcd18 Mon Sep 17 00:00:00 2001 From: Andrii Chernenko Date: Fri, 13 Apr 2018 17:32:07 +0200 Subject: [PATCH 03/10] Fix deprecated dependency definitions --- android/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 090642a..f333cb5 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -19,7 +19,7 @@ android { } dependencies { - compile 'com.facebook.react:react-native:+' - compile 'com.google.android.gms:play-services-gcm:+' - compile 'org.nanohttpd:nanohttpd:2.2.0' + implementation 'com.facebook.react:react-native:+' + implementation 'com.google.android.gms:play-services-gcm:+' + implementation 'org.nanohttpd:nanohttpd:2.2.0' } From d6509e8c89ba4c38f2c5b030373c9a520a8e7739 Mon Sep 17 00:00:00 2001 From: Andrii Chernenko Date: Fri, 13 Apr 2018 17:36:06 +0200 Subject: [PATCH 04/10] Update buildToolsVersion --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index f333cb5..eaa1ebc 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' android { compileSdkVersion 23 - buildToolsVersion "23.0.1" + buildToolsVersion "27.0.3" defaultConfig { minSdkVersion 16 From d80d19fe4f1aeb3b3948ebe8ad07c8dc63fb5f4e Mon Sep 17 00:00:00 2001 From: Andrii Chernenko Date: Fri, 13 Apr 2018 17:42:36 +0200 Subject: [PATCH 05/10] Update SDK version --- android/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index eaa1ebc..4dafb7a 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 23 + compileSdkVersion 26 buildToolsVersion "27.0.3" defaultConfig { minSdkVersion 16 - targetSdkVersion 22 + targetSdkVersion 26 versionCode 2 versionName "1.1" ndk { From 219dd76b291fd73aba32bf9b1d60cec78932d067 Mon Sep 17 00:00:00 2001 From: Andrii Chernenko Date: Fri, 20 Apr 2018 11:50:53 +0200 Subject: [PATCH 06/10] Refactoring, return hostname and port on server start --- .gitignore | 2 + .../RNHttpServer/RNHttpServerModule.java | 175 ++++++-------- .../java/com/strainy/RNHttpServer/Server.java | 221 ++++++++---------- httpServer.js | 125 +++------- 4 files changed, 203 insertions(+), 320 deletions(-) diff --git a/.gitignore b/.gitignore index 5148e52..87082fc 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ jspm_packages # Optional REPL history .node_repl_history + +.idea diff --git a/android/src/main/java/com/strainy/RNHttpServer/RNHttpServerModule.java b/android/src/main/java/com/strainy/RNHttpServer/RNHttpServerModule.java index f1a4b8b..8986793 100644 --- a/android/src/main/java/com/strainy/RNHttpServer/RNHttpServerModule.java +++ b/android/src/main/java/com/strainy/RNHttpServer/RNHttpServerModule.java @@ -1,13 +1,12 @@ package com.strainy.RNHttpServer; -import com.strainy.RNHttpServer.Server; - import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReadableMap; @@ -18,138 +17,96 @@ import java.util.Map; import java.util.HashMap; -import android.support.annotation.Nullable; import android.util.Log; -public class RNHttpServerModule extends ReactContextBaseJavaModule implements LifecycleEventListener { - - ReactApplicationContext reactContext; - - private static final String TAG = "RNHttpServer"; - - private static final String DEFAULT_PORT_KEY = "DEFAULT_PORT"; - private static final String DEFAULT_TIMEOUT_KEY = "DEFAULT_TIMEOUT"; - private static final String SERVER_EVENT_ID_KEY = "SERVER_EVENT"; - - private static final int DEFAULT_PORT = 8080; - private static final int DEFAULT_TIMEOUT = 30000; - private static final String SERVER_EVENT_ID = "reactNativeHttpServerResponse"; - - private int _port; - private int _timeout; +public class RNHttpServerModule extends ReactContextBaseJavaModule { - private Server _server = null; + ReactApplicationContext reactContext; - private Callback _success; - private Callback _failure; + private static final String TAG = "RNHttpServer"; - public RNHttpServerModule(ReactApplicationContext reactContext) { - super(reactContext); + private static final String DEFAULT_PORT_KEY = "DEFAULT_PORT"; + private static final String DEFAULT_TIMEOUT_KEY = "DEFAULT_TIMEOUT"; + private static final String SERVER_EVENT_ID_KEY = "SERVER_EVENT"; - _port = DEFAULT_PORT; - _timeout = DEFAULT_TIMEOUT; + private static final int DEFAULT_PORT = 8080; + private static final int DEFAULT_TIMEOUT = 30000; + private static final String SERVER_EVENT_ID = "reactNativeHttpServerResponse"; - reactContext.addLifecycleEventListener(this); + private static final String ERROR_SERVER_NOT_RUNNING = "ERROR_SERVER_NOT_RUNNING"; + private static final String ERROR_COULD_NOT_START = "ERROR_COULD_NOT_START"; - this.reactContext = reactContext; + private int port; + private int timeout; + private Server server = null; - } - @Override - public String getName() { - return "RNHttpServer"; - } + public RNHttpServerModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; - @Override - public Map getConstants() { - final Map constants = new HashMap<>(); - constants.put(DEFAULT_PORT_KEY, DEFAULT_PORT); - constants.put(DEFAULT_TIMEOUT_KEY, DEFAULT_TIMEOUT); - constants.put(SERVER_EVENT_ID_KEY, SERVER_EVENT_ID); - return constants; - } - - @ReactMethod - public void init(ReadableMap options, Callback success, @Nullable Callback failure) { - - Log.d(TAG, "Initialising server..."); - - if(options.hasKey("port")) { - _port = options.getInt("port"); + port = DEFAULT_PORT; + timeout = DEFAULT_TIMEOUT; } - if(options.hasKey("timeout")) { - _timeout = options.getInt("timeout"); + @Override + public String getName() { + return "RNHttpServer"; } - start(success, failure); - - } - - @ReactMethod - public void start(@Nullable Callback success, @Nullable Callback failure) { + @Override + public Map getConstants() { + final Map constants = new HashMap<>(); + constants.put(DEFAULT_PORT_KEY, DEFAULT_PORT); + constants.put(DEFAULT_TIMEOUT_KEY, DEFAULT_TIMEOUT); + constants.put(SERVER_EVENT_ID_KEY, SERVER_EVENT_ID); - try { + return constants; + } - _server = new Server(reactContext, _port, _timeout); - _server.start(); + @ReactMethod + public void init(ReadableMap options) { + Log.d(TAG, "Initializing server..."); - if(success != null) { - success.invoke(); + if (options.hasKey("port")) { + port = options.getInt("port"); } - } - catch(Exception e) { - Log.e(TAG, e.getMessage()); - - if(failure != null) { - failure.invoke(e.getMessage()); + if (options.hasKey("timeout")) { + timeout = options.getInt("timeout"); } - - } - - } - - @ReactMethod - public void stop() { - Log.d(TAG, "Server Stopped."); - _server.stop(); - _server = null; - } - - @ReactMethod - public void setResponse(String uri, ReadableMap response) { - if(_server != null) { - _server.setResponse(uri, response); } - } - @ReactMethod - public String getHostName() { - if(_server != null) { - Log.d(TAG, _server.getHostname()); - return _server.getHostname(); - } - else { - return "not defined"; + @ReactMethod + public void start(Promise promise) { + try { + server = new Server(reactContext, port, timeout); + server.start(); + port = server.getListeningPort(); + + WritableMap args = Arguments.createMap(); + args.putString("hostname", server.getHostname()); + args.putString("port", String.valueOf(server.getListeningPort())); + + promise.resolve(args); + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + promise.reject(ERROR_COULD_NOT_START, e); + } } - } - - /* Shut down the server if app is destroyed or paused */ - @Override - public void onHostResume() { - //we can restart the server here as the success callback is not needed since an event is registered - start(null, null); - } - @Override - public void onHostPause() { - stop(); - } + @ReactMethod + public void stop() { + if (server == null) { return; } - @Override - public void onHostDestroy() { - stop(); - } + server.stop(); + server = null; + Log.d(TAG, "Server stopped."); + } + @ReactMethod + public void setResponse(String uri, ReadableMap response) { + if (server == null) { return; } + server.setResponse(uri, response); + } } diff --git a/android/src/main/java/com/strainy/RNHttpServer/Server.java b/android/src/main/java/com/strainy/RNHttpServer/Server.java index 9d7eb47..340f24f 100644 --- a/android/src/main/java/com/strainy/RNHttpServer/Server.java +++ b/android/src/main/java/com/strainy/RNHttpServer/Server.java @@ -9,7 +9,6 @@ import java.util.Map; import java.util.Set; -import java.util.Iterator; import java.util.HashMap; import android.support.annotation.Nullable; @@ -20,154 +19,136 @@ public class Server extends NanoHTTPD { private static final String TAG = "RNHttpServer"; - private static final String SERVER_EVENT_ID = "reactNativeHttpServerResponse"; - private Map _response; + private int timeout; private ReactContext reactContext; + private Map response; - private int _timeout; public Server(ReactContext context, int port, int timeout) { super("127.0.0.1", port); reactContext = context; - _timeout = timeout; - _response = new HashMap<>(); - Log.d(TAG, "Server started."); + this.timeout = timeout; + response = new HashMap<>(); } public void setResponse(String uri, ReadableMap response) { - _response.put(uri, response); + this.response.put(uri, response); } @Override public Response serve(IHTTPSession session) { + Log.d(TAG, "Server receiving request."); + + Response.Status errorStatus = null; + String errorText = ""; + int timer = 0; + int interval = 500; + WritableMap request = Arguments.createMap(); + ReadableMap response; + + // build request to send to react-native + Method method = session.getMethod(); + request.putString("url", session.getUri()); + request.putString("method", method.toString()); + request.putMap("headers", this.convertToWritableMap(session.getHeaders())); + request.putString("queryString", session.getQueryParameterString()); + + // bit of complexity around getting the POST/PUT body... + Map files = new HashMap(); + + if (Method.PUT.equals(method) || Method.POST.equals(method)) { + try { + session.parseBody(files); + request.putString("data", files.get(files.keySet().toArray()[0])); + } catch (IOException ioe) { + return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); + } catch (ResponseException re) { + return newFixedLengthResponse(re.getStatus(), MIME_PLAINTEXT, re.getMessage()); + } + } - Log.d(TAG, "Server receiving request."); - - Response.Status errorStatus = null; - String errorText = ""; - int timer = 0; - int interval = 500; - WritableMap request = Arguments.createMap(); - ReadableMap response; - - // build request to send to react-native - Method method = session.getMethod(); - request.putString("url", session.getUri()); - request.putString("method", method.toString()); - request.putMap("headers", this.convertToWritableMap( session.getHeaders() )); - request.putString("queryString", session.getQueryParameterString()); - - // bit of complexity around getting the POST/PUT body... - Map files = new HashMap(); - - if (Method.PUT.equals(method) || Method.POST.equals(method)) { - try { - session.parseBody(files); - request.putString("data", files.get(files.keySet().toArray()[0]) ); - } catch (IOException ioe) { - return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage()); - } catch (ResponseException re) { - return newFixedLengthResponse(re.getStatus(), MIME_PLAINTEXT, re.getMessage()); - } - } - - // send request to react-native - this.sendEvent(reactContext, SERVER_EVENT_ID, request); - - // wait for response - while(!_response.containsKey(session.getUri()) && (timer < _timeout)) { - try { - Thread.sleep(interval); - Log.d(TAG, "waiting for " + session.getUri() + " - " + timer + "ms"); + // send request to react-native + this.sendEvent(reactContext, SERVER_EVENT_ID, request); + + // wait for response + while (!this.response.containsKey(session.getUri()) && (timer < timeout)) { + try { + Thread.sleep(interval); + Log.d(TAG, "waiting for " + session.getUri() + " - " + timer + "ms"); + } catch (InterruptedException e) { + Log.e(TAG, e.getMessage()); + errorStatus = Response.Status.INTERNAL_ERROR; + errorText = e.getMessage(); + break; + } + + timer = timer + interval; } - catch(InterruptedException e){ - Log.e(TAG, e.getMessage()); - errorStatus = Response.Status.INTERNAL_ERROR; - errorText = e.getMessage(); - break; + + // if after waiting x seconds, no response has been logged, throw a 404 response + if (!this.response.containsKey(session.getUri())) { + errorStatus = Response.Status.NOT_FOUND; + errorText = "Resource not found"; + } + + if (errorStatus != null) { + return newFixedLengthResponse(errorStatus, MIME_PLAINTEXT, errorText); + } else { + response = this.response.get(session.getUri()); + this.response.remove(session.getUri()); // clear responses } - timer = timer + interval; - } - - // if after waiting x seconds, no response has been logged, throw a 404 response - if(!_response.containsKey(session.getUri())){ - errorStatus = Response.Status.NOT_FOUND; - errorText = "Resource not found"; - } - - if(errorStatus != null){ - return newFixedLengthResponse(errorStatus, MIME_PLAINTEXT, errorText); - } - else { - response = _response.get(session.getUri()); - _response.remove(session.getUri()); // clear responses - } - - Log.d(TAG, "Sending response for " + session.getUri()); - - Response res = newFixedLengthResponse( - Response.Status.valueOf(response.getString("status")), - response.getString("type"), - response.getString("data") ); - - // Add headers to the response - /*ReadableMap rnHeaders = response.getMap("headers"); - com.facebook.react.bridge.ReadableMapKeySetIterator iterator = rnHeaders.keySetIterator(); - if (!iterator.hasNextKey()) { - return null; - } - while (iterator.hasNextKey()) { - String key = iterator.nextKey(); - Log.d(TAG, key + "=" + rnHeaders.getString(key)); - res.addHeader(key, rnHeaders.getString(key)); - }*/ - res.addHeader("Access-Control-Allow-Origin", "*"); - res.addHeader("Access-Control-Max-Age", "3628800"); - res.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); - res.addHeader("Access-Control-Allow-Headers", "X-Requested-With"); - res.addHeader("Access-Control-Allow-Headers", "Authorization"); - - return res; + Log.d(TAG, "Sending response for " + session.getUri()); + + Response res = newFixedLengthResponse( + Response.Status.valueOf(response.getString("status")), + response.getString("type"), + response.getString("data")); + + // Add headers to the response + res.addHeader("Access-Control-Allow-Origin", "*"); + res.addHeader("Access-Control-Max-Age", "3628800"); + res.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); + res.addHeader("Access-Control-Allow-Headers", "X-Requested-With"); + res.addHeader("Access-Control-Allow-Headers", "Authorization"); + + return res; } // Convenience method for triggering events in react-native private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) { - reactContext - .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) - .emit(eventName, params); + reactContext + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(eventName, params); } // Convert Java maps to WritableMaps for passing to JS private WritableMap convertToWritableMap(Map map) { - WritableMap request = Arguments.createMap(); - - // iterate over map keys and put values into WritableMap - Set> entrySet = map.entrySet(); - for (Map.Entry entry : entrySet) { - - switch(entry.getValue().getClass().getName()){ - case "java.lang.Boolean": - request.putBoolean(entry.getKey().toString(), (Boolean) entry.getValue()); - break; - case "java.lang.Integer": - request.putInt(entry.getKey().toString(), (Integer) entry.getValue()); - break; - case "java.lang.Double": - request.putDouble(entry.getKey().toString(), (Double) entry.getValue()); - break; - case "java.lang.String": - request.putString(entry.getKey().toString(), (String) entry.getValue()); - break; - } - } - - return request; + WritableMap request = Arguments.createMap(); + + // iterate over map keys and put values into WritableMap + Set> entrySet = map.entrySet(); + for (Map.Entry entry : entrySet) { + switch (entry.getValue().getClass().getName()) { + case "java.lang.Boolean": + request.putBoolean(entry.getKey().toString(), (Boolean) entry.getValue()); + break; + case "java.lang.Integer": + request.putInt(entry.getKey().toString(), (Integer) entry.getValue()); + break; + case "java.lang.Double": + request.putDouble(entry.getKey().toString(), (Double) entry.getValue()); + break; + case "java.lang.String": + request.putString(entry.getKey().toString(), (String) entry.getValue()); + break; + } + } + return request; } - } diff --git a/httpServer.js b/httpServer.js index cf3df6f..6402f07 100644 --- a/httpServer.js +++ b/httpServer.js @@ -1,106 +1,49 @@ /** * @providesModule react-native-http-server */ - 'use strict'; +'use strict'; - import { DeviceEventEmitter } from 'react-native'; - import { NativeModules } from 'react-native'; - var RNHS = NativeModules.RNHttpServer; +import {DeviceEventEmitter} from 'react-native'; +import {NativeModules} from 'react-native'; - var validStatusCodes = [ 'ACCEPTED', - 'BAD_REQUEST', - 'CREATED', - 'FORBIDDEN', - 'INTERNAL_ERROR', - 'METHOD_NOT_ALLOWED', - 'NO_CONTENT', - 'NOT_FOUND', - 'NOT_MODIFIED', - 'OK', - 'PARTIAL_CONTENT', - 'RANGE_NOT_SATISFIABLE', - 'REDIRECT', - 'UNAUTHORIZED' ]; +const validStatusCodes = [ + 'ACCEPTED', 'BAD_REQUEST', 'CREATED', 'FORBIDDEN', 'INTERNAL_ERROR', 'METHOD_NOT_ALLOWED', + 'NO_CONTENT', 'NOT_FOUND', 'NOT_MODIFIED', 'OK', 'PARTIAL_CONTENT', 'RANGE_NOT_SATISFIABLE', + 'REDIRECT', 'UNAUTHORIZED', +]; - module.exports = { +const nativeServerModule = NativeModules.RNHttpServer; - // create the server and listen/respond to requests - create: function(options, callback) { +module.exports = { + init: (options, callback) => { + // listen for new requests and retrieve appropriate response + DeviceEventEmitter.addListener('reactNativeHttpServerResponse', async function (request) { + let response = await new Promise((resolve) => { callback(request, resolve); }) - //Validate port - if(options.port == 80){ - throw "Invalid server port specified. Port 80 is reserved."; - } + //Validate status code + if (validStatusCodes.indexOf(response.status) === -1) { + throw new Error("Invalid response status code specified in RNHttpServer options."); + } - // fire up the server - RNHS.init(options, function() { + if (response.type == null) { + response.type = "text/plain"; + } - // listen for new requests and retrieve appropriate response - DeviceEventEmitter.addListener('reactNativeHttpServerResponse', function(request) { + if (response.data == null) { + response.data = ""; + } - var success = true; + if (response.headers == null) { + response.headers = {}; + } - var promise = new Promise(function(resolve, reject){ - callback(request, resolve); - }) - .then(function(response){ + nativeServerModule.setResponse(request.url, response); + }); - //Validate status code - if(validStatusCodes.indexOf(response.status) === 0){ - success = false; - throw "Invalid response status code specified in RNHttpServer options."; - } + nativeServerModule.init(options); + }, - //Set default MIME_TYPE - if(response.type === null){ - response.type = "text/plain"; - } + start: nativeServerModule.start, - //Set default data field to zero length string - if(response.data === null){ - response.data = ""; - } - - if(response.headers === null){ - response.headers = {}; - } - - if(success){ - RNHS.setResponse(request.url, response); - } - - }); - - }); - - }, function(e){ - throw "Could not initialise server: " + e; - }); - - }, - - // attempt to start the instance of the server - returns a promise object that will be rejected or approved - start: function() { - - var promise = new Promise(function(resolve, reject){ - - RNHS.start(function(){ - resolve(); - }, function(){ - reject(); - }); - - }); - - return promise; - - }, - - // effectively pause the instance of the server - stop: function() { - - RNHS.stop(); - - } - - } + stop: nativeServerModule.stop, +} From 7704387fbbb2bcd41670ad39dcf37b1be480fb26 Mon Sep 17 00:00:00 2001 From: Andrii Chernenko Date: Mon, 23 Apr 2018 14:42:43 +0200 Subject: [PATCH 07/10] Fix iOS crash due to missing native Android module --- httpServer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpServer.js b/httpServer.js index 6402f07..d367b9f 100644 --- a/httpServer.js +++ b/httpServer.js @@ -43,7 +43,7 @@ module.exports = { nativeServerModule.init(options); }, - start: nativeServerModule.start, + start: nativeServerModule != null ? nativeServerModule.start : undefined, - stop: nativeServerModule.stop, + stop: nativeServerModule != null ? nativeServerModule.stop : undefined, } From 3cb101d6ddb5b0e034d1f4ccf5db790b313046e3 Mon Sep 17 00:00:00 2001 From: Andrii Chernenko Date: Fri, 15 Jun 2018 18:27:14 +0200 Subject: [PATCH 08/10] Implement file responses --- .../java/com/strainy/RNHttpServer/Server.java | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/android/src/main/java/com/strainy/RNHttpServer/Server.java b/android/src/main/java/com/strainy/RNHttpServer/Server.java index 340f24f..516da60 100644 --- a/android/src/main/java/com/strainy/RNHttpServer/Server.java +++ b/android/src/main/java/com/strainy/RNHttpServer/Server.java @@ -1,20 +1,21 @@ package com.strainy.RNHttpServer; -import fi.iki.elonen.NanoHTTPD; -import com.facebook.react.bridge.ReactContext; +import android.support.annotation.Nullable; +import android.util.Log; import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule; +import fi.iki.elonen.NanoHTTPD; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.HashMap; - -import android.support.annotation.Nullable; -import android.util.Log; - -import java.io.IOException; public class Server extends NanoHTTPD { @@ -102,10 +103,36 @@ public Response serve(IHTTPSession session) { Log.d(TAG, "Sending response for " + session.getUri()); - Response res = newFixedLengthResponse( - Response.Status.valueOf(response.getString("status")), - response.getString("type"), - response.getString("data")); + Response.Status status = Response.Status.valueOf(response.getString("status")); + String type = response.getString("type"); + ReadableMap responseContent = response.getMap("content"); + + Response res; + if (responseContent.hasKey("data")) { + String data = responseContent.getString("data"); + + res = newFixedLengthResponse(status, type, data); + } else if (responseContent.hasKey("filePath")) { + String filePath = responseContent.getString("filePath"); + + try { + File file = new File(filePath); + long responseLength = file.length(); + FileInputStream fileInputStream = new FileInputStream(file); + + res = newFixedLengthResponse(status, type, fileInputStream, responseLength); + } catch (FileNotFoundException e) { + errorStatus = Response.Status.INTERNAL_ERROR; + errorText = "File not found: " + filePath; + + return newFixedLengthResponse(errorStatus, MIME_PLAINTEXT, errorText); + } + } else { + errorStatus = Response.Status.INTERNAL_ERROR; + errorText = "Response is neither file nor text, which is not supported"; + + return newFixedLengthResponse(errorStatus, MIME_PLAINTEXT, errorText); + } // Add headers to the response res.addHeader("Access-Control-Allow-Origin", "*"); @@ -115,7 +142,6 @@ public Response serve(IHTTPSession session) { res.addHeader("Access-Control-Allow-Headers", "Authorization"); return res; - } // Convenience method for triggering events in react-native @@ -127,7 +153,6 @@ private void sendEvent(ReactContext reactContext, String eventName, @Nullable Wr // Convert Java maps to WritableMaps for passing to JS private WritableMap convertToWritableMap(Map map) { - WritableMap request = Arguments.createMap(); // iterate over map keys and put values into WritableMap From 00aaf295aa371f1c20afd6d205b2500f25a41057 Mon Sep 17 00:00:00 2001 From: Andrii Chernenko Date: Wed, 20 Jun 2018 18:55:31 +0200 Subject: [PATCH 09/10] Take query parameters into account when serving a request --- .../java/com/strainy/RNHttpServer/Server.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/android/src/main/java/com/strainy/RNHttpServer/Server.java b/android/src/main/java/com/strainy/RNHttpServer/Server.java index 516da60..09494fe 100644 --- a/android/src/main/java/com/strainy/RNHttpServer/Server.java +++ b/android/src/main/java/com/strainy/RNHttpServer/Server.java @@ -40,7 +40,13 @@ public void setResponse(String uri, ReadableMap response) { @Override public Response serve(IHTTPSession session) { - Log.d(TAG, "Server receiving request."); + String url = session.getUri(); + String queryParameters = session.getQueryParameterString(); + if (queryParameters != null) { + url = url + "?" + queryParameters; + } + + Log.d(TAG, "Receiving request: " + url); Response.Status errorStatus = null; String errorText = ""; @@ -51,7 +57,7 @@ public Response serve(IHTTPSession session) { // build request to send to react-native Method method = session.getMethod(); - request.putString("url", session.getUri()); + request.putString("url", url); request.putString("method", method.toString()); request.putMap("headers", this.convertToWritableMap(session.getHeaders())); request.putString("queryString", session.getQueryParameterString()); @@ -74,10 +80,10 @@ public Response serve(IHTTPSession session) { this.sendEvent(reactContext, SERVER_EVENT_ID, request); // wait for response - while (!this.response.containsKey(session.getUri()) && (timer < timeout)) { + while (!this.response.containsKey(url) && (timer < timeout)) { try { Thread.sleep(interval); - Log.d(TAG, "waiting for " + session.getUri() + " - " + timer + "ms"); + Log.d(TAG, "waiting for " + url + " - " + timer + "ms"); } catch (InterruptedException e) { Log.e(TAG, e.getMessage()); errorStatus = Response.Status.INTERNAL_ERROR; @@ -89,7 +95,7 @@ public Response serve(IHTTPSession session) { } // if after waiting x seconds, no response has been logged, throw a 404 response - if (!this.response.containsKey(session.getUri())) { + if (!this.response.containsKey(url)) { errorStatus = Response.Status.NOT_FOUND; errorText = "Resource not found"; } @@ -97,11 +103,11 @@ public Response serve(IHTTPSession session) { if (errorStatus != null) { return newFixedLengthResponse(errorStatus, MIME_PLAINTEXT, errorText); } else { - response = this.response.get(session.getUri()); - this.response.remove(session.getUri()); // clear responses + response = this.response.get(url); + this.response.remove(url); // clear responses } - Log.d(TAG, "Sending response for " + session.getUri()); + Log.d(TAG, "Sending response for " + url); Response.Status status = Response.Status.valueOf(response.getString("status")); String type = response.getString("type"); From 86250131309a42bd5570194c7344afdaebc20c10 Mon Sep 17 00:00:00 2001 From: Vladyslav Humeniuk Date: Tue, 18 Jun 2019 22:32:56 +0300 Subject: [PATCH 10/10] Fix Google Play releasing breaking update with new gcm version --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 4dafb7a..ab8c6af 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -20,6 +20,6 @@ android { dependencies { implementation 'com.facebook.react:react-native:+' - implementation 'com.google.android.gms:play-services-gcm:+' + implementation 'com.google.android.gms:play-services-gcm:16.0.0' implementation 'org.nanohttpd:nanohttpd:2.2.0' }