[ 
https://issues.apache.org/jira/browse/JAMES-3495?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17302204#comment-17302204
 ] 

Benoit Tellier commented on JAMES-3495:
---------------------------------------

While starting implementing the PUSH in our webMail we encountered the 
following difficulty:

JMAP needs HTTP headers to work: Authorization (for authentication) and Accept 
(to specify jmap version)
Using WebSocket API 
(https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) we cannot send 
HTTP headers.
It is possible with node libraries (https://www.npmjs.com/package/ws, 
https://socket.io/) and with command-line clients 
(https://github.com/vi/websocat) but the aim of jmap-client-ts is to be used on 
web browsers (Firefox, Chrome, ...)
This post on StackOverflow 
(https://stackoverflow.com/questions/4361173/http-headers-in-websockets-client-api)
 explains it is not possible to pass headers with WebSocket API and proposes 
some alternatives.
In the JMAP WebSocket draft 
(https://tools.ietf.org/html/draft-ietf-jmap-websocket-07#section-4.1), there 
is no other way of authentication than the request initiating the WebSocket, so 
with HTTP headers.
This issue (https://github.com/whatwg/html/issues/3062) asks for support of 
HTTP headers for WebSocket on browsers, there is also a comment mentioning JMAP 
(https://github.com/whatwg/html/issues/3062#issuecomment-722021171)

Possible solutions:

 - The WebSocket does not need authentication to be established, the content of 
the HTTP headers are instead sent on the first message by the client.


if no auth header is specified on the HTTP handshake, to expect an 
Authentication ballot as first message:

```
{
 "@type": "Authorization",
 "Authorization":"Bearer GABOUZOMEUH"
}
```

Some alternatives to this approach might be:

 - The content of the HTTP headers are instead transmitted by query parameters 
though it is not very secure.

 - The content of the HTTP headers are instead transmitted by the protocols 
list (this will set a header Sec-WebSocket-Protocol) though this is not what 
the header is intended to do.

> MessageId field in messageIdTable can be null
> ---------------------------------------------
>
>                 Key: JAMES-3495
>                 URL: https://issues.apache.org/jira/browse/JAMES-3495
>             Project: James Server
>          Issue Type: New Feature
>          Components: cassandra, mailbox
>    Affects Versions: 3.6.0
>            Reporter: Benoit Tellier
>            Priority: Major
>             Fix For: 3.6.0
>
>
> I observed some data corruption on one of our production instances, where the 
> user was having one message in its messageIdTable with a null messageId. The 
> imact was a persiting IMAP FETCH error denying the user the access to his 
> mailbox (NPE).
> By that time I did not understand the origin of it, and thought it was due to 
> a hard shutdown.
> After listening to https://www.youtube.com/watch?v=86olupkuLlU while 
> performing some post running stretches, I realized that Discord encountered 
> similar issues while migrating from MongoDB to Cassandra.
> They encountered the very same symptom that were caused by out of order 
> updates. Something like:
> {code:java}
>         CassandraId mailboxId = CassandraId.timeBased();
>         MessageUid messageUid = MessageUid.of(1);
>         CassandraMessageId messageId = messageIdFactory.generate();
>         testee.insert(ComposedMessageIdWithMetaData.builder()
>                 .composedMessageId(new ComposedMessageId(mailboxId, 
> messageId, messageUid))
>                 .flags(new Flags())
>                 .modSeq(ModSeq.of(1))
>                 .build())
>             .block();
>         testee.delete(mailboxId, messageUid).block();
>         testee.updateMetadata(ComposedMessageIdWithMetaData.builder()
>                 .composedMessageId(new ComposedMessageId(mailboxId, 
> messageId, messageUid))
>                 .flags(new 
> Flags(org.apache.james.mailbox.cassandra.table.Flag.ANSWERED))
>                 .modSeq(ModSeq.of(2))
>                 .build())
>             .block();
>         Optional<ComposedMessageIdWithMetaData> message = 
> testee.retrieve(mailboxId, messageUid).block();
>         System.out.println(message);
>         assertThat(message.isPresent()).isFalse();
> {code}
> Would print:
> {code:java}
> Optional[ComposedMessageIdWithMetaData{composedMessageId=ComposedMessageId{mailboxId=CassandraId{id=2662a6e0-60a2-11eb-89ca-8540fda15edb},
>  messageId=CassandraMessageId{uuid=null}, uid=MessageUid{uid=1}}, 
> flags=flagAnswered, modSeq=ModSeq{value=2}}]
> {code}
> How to solve this?
>  - Either ignore the delete. We should thus specify the messageId on each 
> updates so that it cannot end up being null. This ends up updating to much 
> data and likely have a performance impact.
>  - Filter out entries with a null messageId as we know that for sure they 
> were deleted. That is my personal preference.
> We likely need to audit other tables were partial updates are performed, and 
> could result in similar issues.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to