NullPointerException on HttpMessageDecoder.skipControlCharacters in Netty - http

I'm getting strange error when trying to read HTTP request in Netty:
java.lang.NullPointerException
at
org.jboss.netty.handler.codec.http.HttpMessageDecoder.skipControlCharacters(HttpMessageDecoder.java:409)
at org.jboss.netty.handler.codec.http.HttpMessageDecoder.decode(HttpMessageDecoder.java:184)
at org.jboss.netty.handler.codec.http.HttpMessageDecoder.decode(HttpMessageDecoder.java:107)
at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:470)
at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:443)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261)
at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351)
at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:282)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:202)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:679)
the stack trace doesn't end up in my code, and I have no idea how to debug that?
class RouteHandler(default: Tuple2[String, Int]) extends SimpleChannelUpstreamHandler {
override def handleUpstream(ctx: ChannelHandlerContext, e: ChannelEvent) {
e match {
case evt: UpstreamMessageEvent =>
evt.getMessage match {
case req: HttpRequest => {
val projectHdr = req.getHeader("HDR")
RouteHandler.log.info("Project ID: {}", projectHdr)
val backendServerUri = projectHdr match {
case null => default
case uri: String =>
if (ObjectId.isValid(projectHdr)) {
val serverData = MappingService.resolveServer(new ObjectId(projectHdr))
(serverData.host(), serverData.port())
}
else
default
}
RouteHandler.log.info("Route to {}", backendServerUri)
val pipeline = ctx.getPipeline
pipeline.synchronized {
val handler = new ForwardRequestHandler(backendServerUri._1, backendServerUri._2)
pipeline.get(HANDLER_NAME) match {
case null => pipeline.addLast(HANDLER_NAME, handler)
case _ => pipeline.replace(HANDLER_NAME, HANDLER_NAME, handler)
}
}
}
case z => RouteHandler.log.warn("Can not handle {}", z.getClass)
}
case z: DefaultExceptionEvent => RouteHandler.log.error("Exception from Netty", z.getCause)
case z =>
}
super.handleUpstream(ctx, e)
}
override def exceptionCaught(ctx: ChannelHandlerContext, e: ExceptionEvent) {
RouteHandler.log.error("Caught", e.getCause)
e.getChannel.close()
}
}

So just for the record... The error was that the HttpMessageDecoder was shared across Channels which is not allowed as its not annotated witht #Sharable

Related

Running async tcp connection on swiftUi chat app

For a school project, I have to create a swiftUi chat app.
I'm fairly new to swift but managed to use the Network framework to connect to my chat server using the following code :
import Foundation
import Network
class Client {
let connection: Connection
let host: NWEndpoint.Host
let port: NWEndpoint.Port
var queue: DispatchQueue = DispatchQueue.init(label: "keepAlive")
init(host: String, port: UInt16) {
self.host = NWEndpoint.Host(host)
self.port = NWEndpoint.Port(rawValue: port)!
let nwConnection = NWConnection(host: self.host, port: self.port, using: .tcp)
connection = BaburuConnection(nwConnection: nwConnection)
}
func start() {
print("Client started \(host) \(port)")
connection.didStopCallback = didStopCallback(error:)
connection.start()
}
func stop() {
connection.stop()
}
func sendMessage(content: String, channel: UUID) {
let msg = Data(Frame.Message(value: content, channel: channel).serialize())
connection.send(data: msg)
}
func sendCommand(command: CommandKind, args: [String]? = nil) {
let cmd = Data(Frame.Cmd(cmd: Command(kind: command, args: args)).serialize())
connection.send(data: cmd)
}
func isConnected() -> Bool {
return connection.running
}
func didStopCallback(error: Error?) {
if error == nil {
exit(EXIT_SUCCESS)
} else {
exit(EXIT_FAILURE)
}
}
}
import Foundation
import Network
var KeepAlive = 30
var maxReadLength = 4096
class Connection {
let nwConnection: NWConnection
let queue = DispatchQueue(label: "Client connection Q")
var running = false
private var serializedKA = Frame.KeepAlive().serialize()
private lazy var timer = Timer(timeInterval: TimeInterval(KeepAlive), repeats: true) { _ in
self.send(data: Data(Frame.KeepAlive().serialize()))
}
init(nwConnection: NWConnection) {
self.nwConnection = nwConnection
}
var didStopCallback: ((Error?) -> Void)? = nil
func start() {
print("connection will start")
nwConnection.stateUpdateHandler = stateDidChange(to:)
setupReceive()
nwConnection.start(queue: queue)
running = true
DispatchQueue.global(qos: .background).async {
let runLoop = RunLoop.current
runLoop.add(self.timer, forMode: .default)
runLoop.run()
}
}
private func stateDidChange(to state: NWConnection.State) {
switch state {
case .waiting(let error):
connectionDidFail(error: error)
case .ready:
print("Client connection ready")
case .failed(let error):
connectionDidFail(error: error)
default:
break
}
}
private func setupReceive() {
nwConnection.receive(minimumIncompleteLength: 1, maximumLength: maxReadLength) { (data, _, isComplete, error) in
if let data = data, !data.isEmpty {
let message = String(data: data, encoding: .utf8)
print("connection did receive, data: \(data as NSData) string: \(message ?? "-" )")
switch(Frame.parse(reader: BufferedString(str: message!))) {
case .success(let res):
if res is Frame.MessageWrapper {
print("message : ", res)
} else if res is Frame.Cmd {
print("command : ", res)
} else {
print("TODO")
}
case .failure(let err):
print(err)
}
}
if isComplete {
self.connectionDidEnd()
} else if let error = error {
self.connectionDidFail(error: error)
} else {
self.setupReceive()
}
}
}
func send(data: Data) {
nwConnection.send(content: data, completion: .contentProcessed( { error in
if let error = error {
self.connectionDidFail(error: error)
return
}
print("connection did send, data: \(data as NSData)")
}))
}
func stop() {
print("connection will stop")
self.timer.invalidate()
running = false
stop(error: nil)
}
private func connectionDidFail(error: Error) {
print("connection did fail, error: \(error)")
self.stop(error: error)
}
private func connectionDidEnd() {
print("connection did end")
self.stop(error: nil)
}
private func stop(error: Error?) {
self.nwConnection.stateUpdateHandler = nil
self.nwConnection.cancel()
if let didStopCallback = self.didStopCallback {
self.didStopCallback = nil
didStopCallback(error)
}
}
}
The code works fine when I use it with a blocking operation beneath it but I can't think of any good solution for implementing it in mw swiftUi app since I need to keep some sort of reference on the Client object in order to call it's sendMessage and sendCommand methods with a button and notify my ui when I receive a message.
Does anyone has any advises ?
Also, if there is a cleaner way than recursion for async reading, I would gladly change it.

Unexpected text "return"

I'm trying to implement an AuthService from a tutorial of Fireship (https://fireship.io/lessons/flutter-firebase-google-oauth-firestore/)
I copied exactly his AuthService:
AuthService() {
user = Observable(_auth.onAuthStateChanged);
profile = user.switchMap((FirebaseUser u) => {
if (u != null) {
return _db.collection("users").document(u.uid).snapshots().map((snap) => snap.data);
} else {
return Observable.just({});
}
});
}
I get these errors:
If I copy the code from his website (it's exactly the same) there are no errors.
wtf? Can someone explain this or help? Thanks!
Change this:
profile = user.switchMap((FirebaseUser u) => {
into this:
profile = user.switchMap((FirebaseUser u) {
From the docs:
For functions that contain just one expression, you can use a shorthand syntax:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
The => expr syntax is a shorthand for { return expr; }. The => notation is sometimes referred to as arrow syntax.

Error UseHealthChecksUI Unexpected character encountered

I'm trying to implement the ASP.NET Core 2.2 health check feature. Setting up the health check itself isn't the problem, but I also want to be able to use the UI feature in other project to monitoring all my apis. Right now I get the exception message
Unexpected character encountered while parsing value: <.
What I'm doing bad?
API Project:
var healthCheckOptions = new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = async (c, r) =>
{
c.Response.ContentType = MediaTypeNames.Application.Json;
var result = JsonConvert.SerializeObject(
new
{
Checks = r.Entries.Select(e =>
new
{
Description = e.Key,
Status = e.Value.Status.ToString(),
ResponseTime = e.Value.Duration.TotalMilliseconds
}),
TotalResponseTime = r.TotalDuration.TotalMilliseconds
});
await c.Response.WriteAsync(result);
}
};
app.UseHealthChecks("/live", new HealthCheckOptions
{
Predicate = _ => true
});
app.UseHealthChecks("/hc", healthCheckOptions);
app.UseHealthChecksUI(options => options.UIPath = "/healtcheck");
// Registers required services for health checks
services
.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy())
.AddCheck("ComunContext Database", new SqlServerHealthCheck(configuration["ConnectionStrings:ComunContext"]));
Web project:
services.AddHealthChecksUI();
app.UseHealthChecksUI(config =>
{
config.UIPath = "/healthcheck";
});
appsettings.json
{
"HealthChecks-UI": {
"HealthChecks": [
{
"Name": "Local",
"Uri": "http://localhost:27365/hc"
}
],
"EvaluationTimeOnSeconds": 10,
"MinimumSecondsBetweenFailureNotifications": 60
}
}
Try adding a ResponseWriter:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHealthChecks("/healthchecks", new HealthCheckOptions
{
ResponseWriter = async (context, report) =>
{
context.Response.ContentType = "application/json; charset=utf-8";
var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(report));
await context.Response.Body.WriteAsync(bytes);
}
});
app.UseHealthChecksUI();
}
After a few days struggling with this parser error, I've figured out that there are 2 problems:
1 - If you have an Exception, Health UI tries to convert Exception object field, resulting on error;
2 - If you try to pass your own anonymous object, Health UI fails to convert Entries collection, because it need to be an specific anonymous Dictionary.
Try this:
var healthCheckOptions = new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = async (c, r) =>
{
c.Response.ContentType = MediaTypeNames.Application.Json;
var result = JsonConvert.SerializeObject(
new
{
Checks = r.Entries.ToDictionary(
e => e.Key,
e =>
new
{
Description = e.Key,
Status = e.Value.Status.ToString(),
ResponseTime = e.Value.Duration.TotalMilliseconds
}),
TotalResponseTime = r.TotalDuration.TotalMilliseconds
});
await c.Response.WriteAsync(result);
}
};

Running await inside RxJS Observable flatMap

I am trying to return an observable inside an async arrow function passed to a flatMap, but the returned observable is not being called.
protected buildUseCaseObservable(params: LoginUserParams): Observable<Session> {
return this.userRepository.getUserByName(params.getUsername())
.pipe(flatMap(async user => {
if (!user) {
throw new Error(Errors.USER_DOESNT_EXIST);
}
const match = await this.cypher.compare(params.getPassword(), user.password);
if (!match) {
throw new Error(Errors.WRONG_PASSWORD);
}
return Observable.create((subscriber: Subscriber<Session>) => {
subscriber.next(new Session("token test", "refreshToken test"));
subscriber.complete();
});
}));
}
Does anyone knows why does it happen and how can I solve it? Thanks in advance.
Solved, I just turned the promise into an observable and did flatMap it.
protected buildUseCaseObservable(params: LoginUserParams): Observable<Session> {
return this.userRepository.getUserByName(params.getUsername())
.pipe(flatMap(storedUser => {
if (!storedUser) {
throw new Error(Errors.USER_DOESNT_EXIST);
}
return from(this.cypher.compare(params.getPassword(), storedUser.password));
})).pipe(flatMap(match => {
if (!match) {
throw new Error(Errors.WRONG_PASSWORD);
}
return Observable.create((subscriber: Subscriber<Session>) => {
subscriber.next(new Session("token test", "refreshToken test"));
subscriber.complete();
});
}));
}

Bound class method with with generic type

Here is a demo of the problem on tryflow
Essentially I have a class that operates on an array of gerically typed items.
type Props<ItemType> = {
items: ItemType[],
onSelect: (item: ItemType) => void
}
class List<ItemType> {
props: Props<ItemType>
activeIndex: number
constructor(props: Props<ItemType>) {
this.props = props;
this.activeIndex = 0;
}
getActiveItem() : ?ItemType {
return this.props.items[this.activeIndex];
}
submitItem(item: ?ItemType){
if(item) {
this.props.onSelect(item)
}
}
onClick() {
this.submitItem(this.getActiveItem())
}
}
let numbers: number[] = [1,2,3];
let onSelect = (value: number) => {};
let numberList: List<number> = new List({ items: numbers, onSelect: onSelect})
This example comes from a react component that I stripped down to more clearly demonstrate the problem.
It mostly works but ran into problems when I converted submitItem() to a bound method:
submitItem = (item: ?ItemType) => {
if(item) {
this.props.onSelect(item)
}
}
This causes the following error:
27: this.submitItem(this.getActiveItem())
^ Cannot call `this.submitItem` with `this.getActiveItem()` bound to `item` because `ItemType` [1] is incompatible with `ItemType` [2].
References:
8: class List<ItemType> {
^ [1]
20: submitItem = (item: ?ItemType) => {
^ [2]
The method needs to be bound to the class because it will be triggered as a callback from a DOM event.
How do I get the bound method to understand the generic type.
There appears to a problem there with property initialiser syntax (the recommended method of ensuring the method is bound to this) not creating the same type signature as when a regular class property is used. I've raised an issue with a simplified example.
However, in your example you don't seem to need to do this, as your onClick method is the one that needs to be bound and passed as the event handler
// ...
submitItem(item: ?ItemType): void {
if(item) {
this.props.onSelect(item)
}
}
onClick = () => {
this.submitItem(this.getActiveItem())
}
// ...

Resources