My scenario is as follows. I have an Android Emulator which is hosting an EmbedIO web server through an App. When I try to access the URL to the web server from the host machine's (Mac) browser I receive ERR_EMPTY_RESPONSE error.
I have issued the following port forwarding commands through ADB:
adb forward tcp:8080 tcp:8080
In the browser I am navigating to: http://localhost:8080/api/ChangeBackGround
and the Android emulator web server is listening on: http://10.0.2.16:8080/api/ChangeBackGround
Here is the code that starts the web server in the Xamarin Forms App (runs on Android Emulator):
public static class WebServerFactory
{
public static WebServer CreateWebServer<T>(string url, string baseRoute)
where T : WebApiController, new()
{
var server = new WebServer(url)
.WithWebApi(baseRoute, api => api.WithController<T>());
// Listen for state changes.
server.StateChanged += (s, e) => Debug.WriteLine($"WebServer New State - {e.NewState}");
return server;
}
}
public class EventController : WebApiController
{
[Route(HttpVerbs.Get, "/ChangeBackGround")]
public void ChangeBackGround()
{
Device.BeginInvokeOnMainThread(() =>
{
App.Current.MainPage.BackgroundColor = Color.Green;
});
}
}
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
private WebServer _WebServer;
protected override void OnStart()
{
var localIPAddress = GetLocalIPAddress();
var url = $"http://{localIPAddress}:8080";
Task.Factory.StartNew(async () =>
{
_WebServer = WebServerFactory.CreateWebServer<EventController>(url, "/api");
await _WebServer.RunAsync();
});
((MainPage)MainPage).Url = url;
}
private string GetLocalIPAddress()
{
var IpAddress = Dns.GetHostAddresses(Dns.GetHostName()).FirstOrDefault();
if (IpAddress != null)
return IpAddress.ToString();
throw new Exception("Could not locate IP Address");
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}
The scenario currently works on the iOS simulator and an Android physical device. But I always get ERR_EMPTY_RESPONSE even when I've setup the port forwarding rules.
Any help would be much appreciated.
Please first make sure your android emulator could connect internet properly.
If the problem perisist, you can try the following methods:
Method 1:
1.start your Command prompt by runing as an admistrator;
2.Run the following commands in sequence:
netsh int ip reset c:\resetlog.txt
netsh winsock reset
ipconfig /flushdns
exit
Method 2: (If method 1 didn't work,try modthod 2)
Open your Control Panel -->NetWork and Internet-->Network and Sharing Center-->Change adapter settings-->right click Ethenet and click Properties-->select Internet Protocol 4-->click Properties -->using the following NDS server addresses
Fill in the following configuration:
Preferred NDS Server: 1.1.1.1
Alternate NDS Server: 1.0.0.1
Method 3: (If above methods didn't work,try modthod 3)
Open Settings in your PC-->Open NetWork and Internet-->click Nnetwork reset-->press Reset Now
Note:
For more details, you can enter keywords How to fix "ERR_EMPTY_RESPONSE" Error [2021] in your browser and then you will find relative tutorail.
You should have you service listening on either one of these IPs:
127.0.0.1: The emulated device loopback interface (preferred, I don't think you have reasons to use a different one)
10.0.2.15: The emulated device network/ethernet interface
See https://developer.android.com/studio/run/emulator-networking#networkaddresses
Related
I've read a lot of conflicting information about this and it seems people are not 100% clear on what is possible and what is not. I am certain that you cannot host a gRPC server app in IIS due to the HTTP/2 limitations. The documentation is pretty clear. However, I want to use IIS as a reverse proxy, with the internal side communicating using gRPC. So the client would be in IIS, not the server. I assumed that since the communication at this point (i.e. the back end) was not funneled through IIS, there would be no issue with this. However, I keep seeing mixed answers.
I have created a dumb webapp that is hosted in IIS Express and can successfully post to my service running on Kestrel with gRPC.
Client code sample below. The SubmitButton is just a form post on the razor page.
public async void OnPostSubmitButton()
{
// The port number(5001) must match the port of the gRPC server.
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(
new HelloRequest { Name = "GreeterClient" });
Console.WriteLine("Greeting: " + reply.Message);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
Server code is the boilerplate template for gRPC but looks like this:
namespace grpcGreeter
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
namespace grpcGreeter
{
public class GreeterService : Greeter.GreeterBase
{
private readonly ILogger<GreeterService> _logger;
public GreeterService(ILogger<GreeterService> logger)
{
_logger = logger;
}
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply
{
Message = "Hello " + request.Name
});
}
}
}
This works. But, because I keep seeing mixed information saying it that it won't, I am not certain that once I go to deploy the client code (i.e. the reverse proxy), if I will run into problems. I would like to use a host like Azure...but don't know if it's possible or not.
Any clarity on the subject would be greatly appreciated.
As far as I know, we could use asp.net core mvc or razor page application as the client to call the grpc server.
But gRPC client requires the service to have a trusted certificate when you hosted the application on remote server IIS.
If you don't have the permission to install the certificate, you should uses HttpClientHandler.ServerCertificateCustomValidationCallback to allow calls without a trusted certificate.
Notice: this will make the call not security.
Additional configuration is required to call insecure gRPC services with the .NET Core client. The gRPC client must set the System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport switch to true and use http in the server address.
Code as below:
AppContext.SetSwitch(
"System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
var httpClientHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpClientHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(httpClientHandler);
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });
I have grpc dotnet core app, dotnet core version 2.1.
App runs fine when executed on local maschine and accessed from that maschine. When I want to access it from other machine (althought firewall disabled, port opened) I can't access it. I think it is something to the code. I'm not dotnet developer but have some microservice legacy code:). Can it be that problem is in Grpc.Core Server class?
Please help out
Code:
using System;
using System.Collections.Generic;
using System.IO;
using Grpc.Core;
...
static void Main()
{
const int port = 4000;
const string host = "localhost";
var cert = File.ReadAllText("cert.pem");
var key = File.ReadAllText("key.pem");
var keypair = new KeyCertificatePair(cert, key);
var server = GetServer(port, host, keypair);
server.Start();
server.ShutdownTask.Wait();
}
private static Server GetServer(int port, string host, KeyCertificatePair keypair)
{
return new Server
{
Services = { SomeService.BindService(new SomeServiceImpl()) },
Ports = { new ServerPort(host, port, new SslServerCredentials(new List<KeyCertificatePair>
{
keypair
}))}
};
}
Your code explicitly says const string host = "localhost"; which means that it will only listen on the loopback interface (= not accessible from other machines). Use e.g. "[::]" or "0.0.0.0" to listen on all network interfaces.
I've devloped a chat bot application using the Facebook Messenger platform.
I used Spring Boot with embedded Tomcat for the web platform.
The application should run on Amazon aws, open to the WWW, and to be used as a webhook for recieving callbacks from Messenger over https.
I need an advice how to secure the application, so it won't be hacked or flooded with requests that are not coming from Facebook.
I thought to make the application require secured (ssl) connection, but using the "security.require_ssl=true" in application.properties didn't do the work. Perhaps I don't know what is the meaning of this and how to configure it propertly.
Is there a best practice how to block requests which are not https requests? Or a way to block requests which are coming outside Messenger in the application level?
Thank you very much!
EDIT
In the meantime, I blocked requests from other IPs in application layer using the handler interceptor:
#Configuration
public class MyWebApplicationInitializer implements WebApplicationInitializer, WebMvcConfigurer{
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptor() {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (! (request.getRemoteAddr().equals("173.252.88.66") || request.getRemoteAddr().equals("127.0.0.1")|| request.getRemoteAddr().equals("0:0:0:0:0:0:0:1"))){
logger.warn("Request is not coming from authorized remote address: " + request.getRemoteAddr()+". Rejecting");
response.getWriter().write("Unauthorized Address");
response.setStatus(401);
return false;
} else {
return true;
}
}
}
You should check the X-Hub-signature HTTP header available in the requests sent by Facebook to your webhook URL.
In your case, you may define a filter or interceptor for the verification of the signature. You can also do it in your controller as in the this example I found in RealTimeUpdateController.java from the spring social project.
private boolean verifySignature(String payload, String signature) throws Exception {
if (!signature.startsWith("sha1=")) {
return false;
}
String expected = signature.substring(5);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
SecretKeySpec signingKey = new SecretKeySpec(applicationSecret.getBytes(), HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(payload.getBytes());
String actual = new String(Hex.encode(rawHmac));
return expected.equals(actual);
}
a lot to say so I am sure I will miss some points.
setting SSL is a first good thing but make sure you get a certificate. lets encrypt is a good thing if you dont want to pay for SSL certificate.
Just seeing aws provides an alternative to letsencrypt
Security Group You can see Security Group as something similar to a firewall so you can control which port is opened, external and internal flows.
Look at IAM which control who and how can get access to your AWS account
obvious : change your password. do not let default password for installation you could make on the instance
read some of https://aws.amazon.com/security/security-resources/ to get more information about what you can do
it won't be hacked or flooded with requests
sorry to say but most probably it will be - It does not need to be an advanced hacker to run scanner and scan IPs and check open ports / brute force login etc ...
Thanks to Guy Bouallet help I added the signature check.
I added it in my controller and not in the interceptor, to avoid the problem of How to read data twice in spring which seems a little complicated.
So here is it:
#RequestMapping(path = "/")
public void doHandleCallback(#RequestBody String body, #RequestHeader(value = "X-Hub-Signature") String signature) throws IOException {
if (!verifyRequestSignature(body.getBytes(), signature)){
logger.error ("Signature mismatch.");
throw new MismatchSignatureException(signature);
}
MessengerCallback callback = mapper.readValue(body, MessengerCallback.class);
logger.info("Incoming Callback: " + body );
for (EventData entry : callback.getEntry()) {
for (ReceivedMessagingObject message : entry.getMessaging()) {
if (message.isMessage() || message.isPostback()) {
doHandleMessage(message);
}
else if (message.isDelivery()){
doHandleDelivery(message);
}
}
}
}
private boolean verifyRequestSignature(byte[] payload, String signature) {
if (!signature.startsWith("sha1="))
return false;
String expected = signature.substring(5);
System.out.println("Expected signature: " + expected); //for debugging purposes
String hashResult = HmacUtils.hmacSha1Hex(APP_SECRET.getBytes(), payload);
System.out.println("Calculated signature: " + hashResult);
if (hashResult.equals(expected)) {
return true;
} else {
return false;
}
}
And this is the Exception handling class:
#ResponseStatus(value=HttpStatus.BAD_REQUEST, reason="Request Signature mismatch")
public class MismatchSignatureException extends RuntimeException {
private String signature;
public MismatchSignatureException(String signature) {
this.signature = signature;
}
#Override
public String getMessage() {
return "Signature mismatch: " + signature;
}
I have a solution in which i am using SignalR. There is a Hub in one of the projects and SignalR.Client in the others that are connecting to that Hub.
This solution is hosted on two servers, and I have a strange problem. In one server everything works fine, but in the other i get an 404 not found error when I am trying to establish the connection from the SignalR.Client.
Hub Code:
public class GlobalHub : Hub
{
public void Hello()
{
Clients.All.hello();
}
public void Notify(string user,NotificationViewModel model)
{
Clients.Group(user).notify(model);
}
public override System.Threading.Tasks.Task OnConnected()
{
string name = Env.UserId().ToString();
Groups.Add(Context.ConnectionId, name);
return base.OnConnected();
}
}
Global.asax Hub Map:
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true,
EnableJavaScriptProxies = true
};
RouteTable.Routes.MapHubs("/signalr",hubConfiguration);
The connection attempt:
string portal = CommonHelper.GetPortalUrl("user");
if(portal.Contains(":50150"))
{
portal = portal.Replace(":50150", "");
}
var connection = new HubConnection(portal+"signalr",false);
IHubProxy myHub = connection.CreateHubProxy("GlobalHub");
connection.Start().Wait();
myHub.Invoke("Notify", userID.ToString(), result2);
I am pretty sure that my connection url is correct, I checked it 50 times.
Error occurs on this line:
onnection.Start().Wait();
SS of Error:
Thanks
The problem may be that when hosting a SignalR project on two servers, clients connected to one can only be connected to other clients connected to the same server. That is because SignalR doesn't automatically broadcast a message through all servers.
http://www.asp.net/signalr/overview/performance/scaleout-in-signalr
Try have a look here and I hope it is helpful to you. One of the proposed solution is to use the Redis Pub/Sub (http://redis.io/topics/pubsub) solution, or Azure Service Bus (http://azure.microsoft.com/en-us/services/service-bus/) - both of whom are use as a backplane (when a server receives a message, it is broadcast to all of them and the one that needs it can use it).
Thanks I solved the problem. It turned out that it was a problem with the server. The server itself couldnt recognize that url (throws 404 on the url).
After that problem was fixed, SignalR started working
I have added the web service to my WPF windows phone store app, when i run my app in emulator it works, but sometime it get creshes cause lack of internet connectivity.
i'm checking my emulator IMEI is registerd or not in database using WCF service on main_pageload event
my code looks like this
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
SchoolWebService.SchoolAppWebServiceSoapClient proxy = new SchoolAppWebServiceSoapClient();
proxy.CheckIMEIRegisteredOrNotCompleted += new EventHandler<CheckIMEIRegisteredOrNotCompletedEventArgs>(proxy_CheckIMEIRegisteredOrNotCompleted);
proxy.CheckIMEIRegisteredOrNotAsync(strIMEI);
}
in this service im checking the mobile IMEI registerd or not. i have checked by debugging the app it goes upto proxy.CheckIMEIRegisteredOrNotAsync(strIMEI);
when it leave the context it throuw the error
An exception of type 'System.ServiceModel.CommunicationException' occurred in System.ServiceModel.ni.dll but was not handled in user code
please suggest me some advice,,,thanks in advance
To check if the Internet connection is available I just simply create a method to check it and execute it then application is launching or page is loading. This method I create in App.xaml.cs:
public bool CheckInternetConnection()
{
bool connection = true;
ConnectionProfile currentConnection = NetworkInformation.GetInternetConnectionProfile();
if (currentConnection == null)
{
connection = false;
}
return connection;
}
Then in some page_loaded event I execute it:
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
bool connection = ((App)Application.Current).CheckInternetConnection();
if (connection == false)
{
MessageBox.Show("Internet connection is not available", "Internet connection", MessageBoxButton.OK);
Application.Current.Terminate();
}
}
Now then a client don't have the Internet connection available it won't crash, but it will show a message for the user. I hope it will help.