How does the Camel Jetty component work in Akka? - apache-camel

In the following example (taken from Akka Camel doc), the Jetty HTTP component is used to receive HTTP messages. Does it mean that the actor start a new Jetty server?
import akka.camel.{ CamelMessage, Consumer }
class MyEndpoint extends Consumer {
def endpointUri = "jetty:http://localhost:8877/example"
def receive = {
case msg: CamelMessage => { /* ... */ }
case _ => { /* ... */ }
}
}

Correct, jetty consumer will start an embedded Jetty server and bind it to the specified port.
Here's a quote from the official documentation:
The jetty component provides HTTP-based endpoints for consuming and producing HTTP requests. That is, the Jetty component behaves as a simple Web server.

Related

Why won't my React app send HTTP-only cookies in WebSocket upgrade requests in production?

I'm currently building a full-stack TypeScript live chat app with React + Vite on the frontend and Node on the backend. I have two separate servers running: one is a REST API and OAuth2 auth server built with Express and Passport.js and the other one is a WebSockets server built with the ws package. They run independently (no interprocess communication whatsoever) and use stateless auth in the form of JWTs.
Here's how my current flow works: users first log in with either their Google or GitHub account, and once the first server has verified their identity, it sends an HTTP-only cookie down to the client. This cookie is send back to the server on all subsequent requests and I have some middleware that runs on the REST API to parse and verify the JWTs on protected routes. Once it has the cookie, the client then initiates a WS connection with the second server, which also checks for the JWT cookie in the incoming HTTP Upgrade request and verifies its signature before allowing the new client to continue exchanging messages:
import { WebSocket, WebSocketServer } from "ws";
import { baseDataSchema } from "./zod/schemas";
import prisma from "./prisma";
import { asyncJWTverify } from "./misc/jwt";
import { UserJwtReceived } from "../types/jwt";
import { handleJoinGroup } from "./websockets-handlers/join-group";
// Websockets server setup
const wss = new WebSocketServer({ port: Number(process.env.WS_PORT) });
const userSocketMap = new Map<string, WebSocket>();
wss.on("listening", () => {
console.log(`WebSockets server started on port ${process.env.WS_PORT}`);
});
wss.on("connection", async function connection(ws, req) {
// authenticate incoming websocket connection
const cookies = req.headers.cookie;
if (!cookies) return ws.close();
let currentUser: UserJwtReceived = { id: "", iat: 0 };
try {
// Decode auth JWT
const token = cookies.split("=")[1];
currentUser = (await asyncJWTverify(
token,
process.env.JWT_SECRET as string
)) as UserJwtReceived;
} catch (err) {
console.error(err);
return ws.close();
}
// check for JWT expiry
const expiryTime = Number(process.env.JWT_EXPIRY);
if (Math.round(Date.now() / 1000) - currentUser.iat > expiryTime) {
return ws.close();
}
// Bind user ID to WebSocket, add it to map
// TypeScript doesn't complain about this because I've extended ws's WebSocket interface
ws.userId = currentUser.id;
userSocketMap.set(currentUser.id, ws);
console.log(`User ID ${ws.userId} connected`);
ws.on("message", async function message(rawData) => {
// ... actual app logic goes here
})
ws.on("close", function () {
if (!ws.userId) return;
console.log(`User ID ${ws.userId} has disconnected`);
userSocketMap.delete(ws.userId);
});
})
Both servers and the React frontend app run on different URLs, both on local dev and prod, so all requests are cross-origin, but CORS is enabled on the REST API/auth server and as far as I know the WebSockets protocol doesn't implement any CORS policies...
The problem I'm currently facing is that in my local dev environment, the cookie that contains the JWT is sent along with Upgrade request no problem, but after deploying my app to AWS Lightsail (it's a VPS service similar to EC2) and setting up NGINX, my React frontend is no longer able to include the cookie with the upgrade request.
After spending literally the whole day debugging, I've been able to rule out a faulty NGINX config as the root of the problem, since I can use wscat to connect (and most importantly, successfully authenticate) to my production WS server by manually including the Cookie header.
I still have no idea why my React app won't properly send the HTTP-only auth cookie to my WS server. Does anyone have any clue as to why this is happening?
I expected the HTTP-only cookie containing the JWT to be sent along with the HTTP Upgrade request, just like I've been able to do in my local dev environment, but no luck.

Axios API request from React Native frontend to local spring backend service not working

I develop a React Native mobile app and for the backend I want to use Java Spring.
Now I have a standalone backend server running locally on port 8080 and my react native app is runned via Expo Go app with npm start.
For this question I have built a very simple example.
In the frontend application I want to do a GET request to retrieve a string back from the backend and I am using axios to send API requests.
The problem is that I get a Network Error error whenever I send the GET request to http://localhost:8080/
// dont bother func name
const loginUser = () => {
axios.get("http://localhost:8080/").then(value => {
console.log(value)
}).catch(err => {
console.log("REQUEST FAILED")
console.log(err)
})}
This is the handler when user presses a button axios request is send, Expected output: "Hello World"
output:
REQUEST FAILED
Network Error
at node_modules\axios\lib\core\createError.js:17:22 in createError
at node_modules\axios\lib\adapters\xhr.js:120:6 in handleError
at node_modules\event-target-shim\dist\event-target-shim.js:818:20 in EventTarget.prototype.dispatchEvent
at node_modules\react-native\Libraries\Network\XMLHttpRequest.js:600:10 in setReadyState
at node_modules\react-native\Libraries\Network\XMLHttpRequest.js:395:6 in __didCompleteResponse
at node_modules\react-native\Libraries\vendor\emitter\EventEmitter.js:189:10 in emit
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:416:4 in __callFunction
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:109:6 in __guard$argument_0
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:364:10 in __guard
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:108:4 in callFunctionReturnFlushedQueue
#RestController
//#CrossOrigin(origins = "*")
public class TestController {
#GetMapping("/")
public String hello(){
return "Hello World";
}
}
Simple Spring REST Controller
#SpringBootApplication
public class JpaApplication {
public static void main(String[] args) {
SpringApplication.run(JpaApplication.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET","POST","PUT","DELETE").allowedHeaders("*").allowedOrigins("*");
}
};
}
}
CORS Config just allowing all
I have tried putting the annotation #CrossOrigin(origins = "*") above the controller but it did not help (seen from: React and Axios : Axios Can't Access Java/SpringBoot REST Backend Service Because of CORS Policy). I have allowed all access from all locations in the CORS config but I get the same output. The example is very simple. I just want to get a simple string back and the solution is probably also very simple but after so many tries I can't come up with a solution. If I visit the URL on the browser I get the expected value, but via axios request it does not seem to work.
After some more searching I found it is not possible to send requests directly to localhost on a Android emulator, on IOS there is no problem. So the problem was after all on the React Native side.
So the fix was relatively easy and also found on stackoverflow, the following thread helped a lot: React Native Android Fetch failing on connection to local API.
I Installed ngrok and this generates a URL which I can use to temporary test my backend till I have hosted it.

File Poller implementation in Spring Boot-Camel Application

I am new to Apache Camel Framework. I have to develop an application in Spring Boot and Camel which polls given directory repeatedly(even after the directory undergo any modifications, the poller should go on polling for another scheduled interval and so on.
I found something like below code in camel.
public class FilePoller extends RouteBuilder {
#Override
public void configure() {
from("file:H:\\InputFolder?delay=1000&noop=true")
.process(new Processor() {
public void process(Exchange msg) {
File file = msg.getIn().getBody(File.class);
//LOG.info("Processing file: " + file);
System.out.println("Polling file:"+file);
}
});
}
}
The above code only waits for 1 second and then execute the subsequent code without polling the directory.
Can anybody help me in developing a Spring Boot-Camel application that polls a directory or a file repeatedly every given interval of time. Thanks in advance
Refer this camel file component documentation.
https://github.com/apache/camel/blob/master/camel-core/src/main/docs/file-component.adoc
To integrate with Spring boot you need to use SB version < 2.0

Access remote service using GWTP Rest Dispatch

I want to separate packages for UI and backend development of my GWTP app.
Currently my UI access the backend using Rest dispatch configured like this:
bindConstant().annotatedWith(RestApplicationPath.class).to("/MyProject/api");
I want to access remote service using localhost UI (running GWT app using eclipse plugin). I changed the above line to:
bindConstant().annotatedWith(RestApplicationPath.class).to("http://my-app.appspot.com/MyProject/api");
Using this, call successfully reaches server ( I can see this in appengine logs) but UI always gets back status code 0.
What is wrong with above setup? Do I have to do something else to access remote service using GWT ui ?
If you want to have a solution that works both on localhost/App Engine, you'd want to use something like this:
import com.google.gwt.core.client.GWT;
import com.google.gwt.inject.client.AbstractGinModule;
import com.google.inject.Provides;
import com.gwtplatform.dispatch.rest.client.RestApplicationPath;
import com.gwtplatform.dispatch.rest.client.gin.RestDispatchAsyncModule;
public class ServiceModule extends AbstractGinModule {
#Override
protected void configure() {
install(new RestDispatchAsyncModule.Builder().build());
}
#Provides
#RestApplicationPath
String getApplicationPath() {
String baseUrl = GWT.getHostPageBaseURL();
if (baseUrl.endsWith("/")) {
baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
}
return baseUrl + "/MyProject/api";
}
}
The string returned by getApplicationPath will be bound to #RestApplicationPath and used seamlessly by GWTP's RestDispatch.
In your case, the string will resolve to http://localhost:8080/MyProject/api or "http://my-app.appspot.com/MyProject/api" depending on the app running locally or on App Engine.

Cannot set protocol version on Camel http component URI

To disable HTTP connection persistency I would like to enforce HTTP protocol 1.0 on one of my Apache Camel routes using the http component.
Following Camel's http component documentation I tried to use the following URI:
http://localhost:8888/foo?httpClient.protocolVersion=HTTP/1.0
However, the camel context initialization fails with a ResolveEndpointFailedException with message:
Unknown parameters=[{protocolVersion=HTTP/1.0}]
I assumed that the protocol version parameter is available due to the HttpClientParam documentation. Interestingly, the soTimeout example from the Apache Camel documentation works fine.
I tried both the http and http4 components. I use Apache Camel 2.10.4. The http component has the user agent Jakarta Commons-HttpClient/3.1.
I know that I could also try to use the httpClientConfigurer and/or clientConnectionManager parameters of the http components, but would rather use a solution that does not require custom code.
Thanks in advance for any help!
I came up with the following solution.
On the http-component URL I set a custom httpClientConfigurer:
http://localhost:8080/foo?httpClientConfigurer=myHttpClientConfigurer
where myHttpClientConfigureris a bean with an implementation similar to this:
public class Http10ClientConfigurer implements HttpClientConfigurer {
#Override
public void configureHttpClient(HttpClient httpClient) {
if (httpClient.getParams() != null) {
httpClient.getParams().setVersion(new HttpVersion(1, 0));
} else {
// Could not set HTTP 1.0 version on httpClient
}
}
}

Resources