-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Simple Websocket & HTTP client API support #19025
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
cd2eb4b to
9330e9e
Compare
9330e9e to
1314acc
Compare
1314acc to
7ee3687
Compare
7ee3687 to
2f20e08
Compare
2f20e08 to
b30d83f
Compare
b30d83f to
e18f77b
Compare
|
Verified that http-client sample works with TLS. Added README files to both samples. |
rlubos
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gone through most of the code, it looks that a lot of work was put into this!
subsys/net/lib/websocket/websocket.c
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any particular reason to use semaphore here instead of mutex?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No particular reason for that, just re-using older code that used semaphore.
e18f77b to
7c49fd0
Compare
|
Updated according to comments. |
7c49fd0 to
226dd51
Compare
dbkinder
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some suggested edits...
226dd51 to
118d1cd
Compare
dbkinder
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for doc changes
1e67202 to
023d898
Compare
|
Fixed the handling of Sec-Websocket-Accept field in HTTP header. |
rlubos
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks
|
Sorry, I was on vacation, then at the conference, so late to the party. Commenting first just based on the textual description and comments here.
Didn't we discussed once that having gigantic parameter list is worse than a dedicated structure to capture those params instead? Some params are strange to, e.g.:
"sockets" and "callbacks" are generally don't mix together. How events are reported for sockets are via pull-style poll() call (instead of push-style callback). If you (for some reason) try to represent high-level websocket communication channel as a system socket, so callbacks, again, look strange.
Why structure of type "http_parser_settings" is named as if it was callback?
What if I don't have all the headers preallocated as single static array (e.g., don't have enough memory for that)?
The first part seems to contradict the second. So, does it issue connect() call? It shouldn't. And if doesn't, then I'd skip mentioning that it "will connect to the server". Mentioning "do needed HTTP handshakes" should be enough, perhaps elaborating it to "will do needed HTTP/Websocket handshake on already established connection".
If it returns file descriptor, that's our old good friend layering violation. Why conjugate high-level websocket connection to pretend it's a system-level socket. No other (sane) system does that. There're immediate portability implications, e.g. you can't test this websocket code on Linux with comfort it gives, so it's likely has bugs. And if it doesn't try to represent itself as a system-level socket, why return an int, instead of structure pointer?
Hey, that's cool! But what about received data? ;-) |
Websocket is SOCK_STREAM protocol, and SOCK_STREAM sockets don't work in terms of "TCP segments", they work in terms of "streams of bytes". So, if BSD Socket API was properly used to implement websocket code, this error couldn't happen in first place... I'm now a bit afraid to look into the actual code... |
include/net/http_client.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned earlier, callback paradigm is counter to native socket paradigm.
include/net/http_client.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned earlier, callback paradigm is counter to native socket paradigm.
include/net/http_client.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say http parser settings is implementation detail of HTTP API, not interesting to the user, but who knows...
subsys/net/lib/http/http_client.c
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is do {} while (true), can you make it while (true) {}, because that's the standard idiom for infinite loop.
The Websocket is a message protocol on top of stream protocol (TCP). IMHO it is not very well designed in the first place but we need to cope with this. |
Do you have a proposal how to pass the params?
The struct contains HTTP callback pointers.
That is not possible with this API. We would probably need to have a callback to feed extra headers to the stream.
There is no contradiction here, user is responsible to call connect(), the websocket API will then connect i.e., establish, like doing handshakes etc., a valid connection to websocket server.
We want to use socket descriptor that is tied to websocket connection. This helps to run things on top of websocket connection and use recv()/send() API. We are not making Linux applications here, and if you want to run valgrind etc you can use native_posix for that.
recv() works just fine too |
023d898 to
e715697
Compare
|
Changing slightly the API proposal:
|
Not something specific, beyond moving all (most) params to a struct, and passing a pointer to it to the function. I see that you already pushed something along those lines, let me have a look. |
include/net/http_client.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why user_data is passed as a separate param and is not part of struct http_request? (Just in case, I'm asking, not calling for change.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many APIs in networking side etc. have typically timeout and user_data parameters in function calls. Just followed this style here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just followed this style here.
Makes sense.
pfalcon
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reviewed this PR, and agree that it's useful and good deal of effort went into it. I appreciate reacting to some suggestions I've made. I have to say that I'm still not fully satisfied with it due to the fact that HTTP API uses callbacks instead of pull-style, socket-style read()/write() functions (as proposed in #13212). So, I'd give this +0.4, which rounds to +0.
At the same time, I understand why it's done like that - callbacks ultimately come from 3rd-party HTTP protocol parser we use, and "masking" them would just take extra effort, especially if the real task here was implementing Websocket support. The concern with callbacks is their known composability issues, but this very PR somehow counter-proves that, as it was possible to implement socket-style API for websocket on top of the underlying callback-style HTTP API (though it's unclear what issues may be lurking there) . So, overall, I don't think I'd come up with an overall better initial implementation even if I tried a callback-less route.
I definitely hope this will be merged soonish, to allow more people to play with it. In that regard, if my approval would help to merge it sooner rather than later, I'd be happy to give my +1 just for that reason, even though I'm not fully satisfied with the overall design.
jukkar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noticed some typos and minor nits when doing self review. I will fix these.
Simple HTTP client API. Signed-off-by: Jukka Rissanen <[email protected]>
Simple HTTP client sample that connects to HTTP server and does GET and POST requests. Signed-off-by: Jukka Rissanen <[email protected]>
4204720 to
9800b29
Compare
Implement simple API to do Websocket client requests. Signed-off-by: Jukka Rissanen <[email protected]>
This is BSD sockets based application for connecting to Websocket server. Signed-off-by: Jukka Rissanen <[email protected]>
Add "net websocket" command that displays websocket information. Signed-off-by: Jukka Rissanen <[email protected]>
9800b29 to
ec321f4
Compare
|
Noticed some fd leaks when closing the connection, those are now fixed. |
|
Seems to work ok now. I have been running mqtt_publisher over Websocket without any issues. |
This PR provides a simple Websocket client API to send Websocket messages to Websocket server. Because the Websocket is established using HTTP, there is small and simple HTTP client API implemented. This HTTP client API can be used to connect to HTTP(S) servers so it is not tied to Websocket client implementation. As this HTTP API is very much needed by Websocket API, I decided not to send it separately to review.
The Websocket API provides functions that can be used by BSD socket API or if more fine grained Websocket support is needed, a Websocket specific API functions are provided.
The main function is this one
It will be given a socket descriptor to the Websocket server. This means that all the non-websocket related things are done outside of this API. The
websocket_connect()will connect to the server, do needed HTTP handshakes and return a new websocket socket descriptor that, when used, will add Websocket header to the sent data. User can then either use normalsend()orwebsocket_send_msg()functions to send the data.One usecase for this API is run MQTT data on top of it. This MQTT support is not part of this PR but to be done separately.