Skip to content
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

[WIP] Ensure request callback is invoked on client connection error #1939

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Sming/Components/Network/src/Network/Http/HttpClientConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ void HttpClientConnection::reset()
HttpConnection::reset();
}

void HttpClientConnection::onError(err_t err)
{
HttpConnection::onError(err);

auto request = waitingQueue.peek();

if(request != nullptr) {
auto callback = request->requestCompletedDelegate;
if(callback) {
callback(*this, false);
}
}
}

int HttpClientConnection::onMessageBegin(http_parser* parser)
{
incomingRequest = executionQueue.peek();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class HttpClientConnection : public HttpConnection

// TCP methods
void onReadyToSendData(TcpConnectionEvent sourceEvent) override;
void onError(err_t err) override;

void onClosed() override;

Expand Down
2 changes: 1 addition & 1 deletion Sming/Components/Network/src/Network/Http/HttpRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class HttpRequest
*/
String getQueryParameter(const String& name, const String& defaultValue = nullptr) const
{
return static_cast<const HttpParams&>(uri.Query)[name] ?: defaultValue;
return uri.getQueryParam(name, defaultValue);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions Sming/Components/Network/src/Network/Url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ Url& Url::operator=(String urlString)
return *this;
}

String Url::getScheme() const
{
if(!Scheme) {
return URI_SCHEME_DEFAULT;
}
String s = Scheme;
s.toLowerCase();
return s;
}

int Url::getDefaultPort(const String& scheme)
{
#define XX(name, str, port) \
Expand Down
16 changes: 15 additions & 1 deletion Sming/Components/Network/src/Network/Url.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ class Url
return toString();
}

/**
* @brief Get the applicable scheme, using the default if not specified
* The returned string is always lowercase.
*/
String getScheme() const;

/** @brief Obtain the default port for a given scheme
* @retval int 0 if scheme is not recognised or has no standard port defined
*/
Expand All @@ -132,7 +138,7 @@ class Url
*/
int getPort() const
{
return Port ?: getDefaultPort(Scheme);
return Port ?: getDefaultPort(getScheme());
}

/** @brief Get hostname+port part of URL string
Expand Down Expand Up @@ -166,6 +172,14 @@ class Url
*/
void debugPrintTo(Print& p) const;

/**
* @brief Get a query parameter without risk of modification
*/
const String& getQueryParam(const String& name, const String& defaultValue = nullptr) const
{
return Query[name] ?: defaultValue;
}

public:
String Scheme; ///< without ":" and "//"
String User;
Expand Down
30 changes: 30 additions & 0 deletions Sming/Components/Network/src/Network/WebsocketClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,27 @@ class WebsocketClientConnection : public HttpClientConnection
// Prevent HttpClientConnection from resetting our receive delegate set by activate() call
err_t onConnected(err_t err) override
{
debug_i("%s CONNECTED", __PRETTY_FUNCTION__);

if(err == ERR_OK) {
state = eHCS_Ready;
}

// IMPORTANT: Skip HttpClientConnection implementation
return HttpConnection::onConnected(err);
}

void onClosed() override
{
debug_i("%s CLOSED", __PRETTY_FUNCTION__);
HttpClientConnection::onClosed();
}

void onError(err_t err) override
{
debug_i("%s ERROR %d", __PRETTY_FUNCTION__, err);
HttpClientConnection::onError(err);
}
};

HttpConnection* WebsocketClient::getHttpConnection()
Expand All @@ -45,15 +59,18 @@ HttpConnection* WebsocketClient::getHttpConnection()

bool WebsocketClient::connect(const Url& url)
{
debug_i("%s CONNECT", __PRETTY_FUNCTION__);
uri = url;
bool useSsl = (uri.Scheme == URI_SCHEME_WEBSOCKET_SECURE);

HttpConnection* httpConnection = getHttpConnection();
if(httpConnection == nullptr) {
debug_i("%s NO CONNECTION", __PRETTY_FUNCTION__);
return false;
}

if(httpConnection->isProcessing()) {
debug_i("%s PROCESSING", __PRETTY_FUNCTION__);
return false;
}

Expand All @@ -74,19 +91,32 @@ bool WebsocketClient::connect(const Url& url)
request->headers[HTTP_HEADER_SEC_WEBSOCKET_PROTOCOL] = F("chat");
request->headers[HTTP_HEADER_SEC_WEBSOCKET_VERSION] = String(WEBSOCKET_VERSION);
request->onHeadersComplete(RequestHeadersCompletedDelegate(&WebsocketClient::verifyKey, this));
request->onRequestComplete([this](HttpConnection& client, bool successful) -> int {
debug_w("XXXXX successful %u", successful);
if(state != eWSCS_Open && wsDisconnect) {
wsDisconnect(*this);
}
return 0;
});

if(!httpConnection->send(request)) {
debug_i("%s SEND", __PRETTY_FUNCTION__);
return false;
}

WebsocketConnection::setUserData(this);

debug_i("%s CONNECTING", __PRETTY_FUNCTION__);

return true;
}

int WebsocketClient::verifyKey(HttpConnection& connection, HttpResponse& response)
{
debug_i("%s", __PRETTY_FUNCTION__);

if(!response.headers.contains(HTTP_HEADER_SEC_WEBSOCKET_ACCEPT)) {
debug_e("[WS] Websocket Accept missing from headers");
state = eWSCS_Closed;
return -2; // we don't have response.
}
Expand Down
5 changes: 4 additions & 1 deletion tests/HostTests/modules/Network/Url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ class UrlTest : public TestGroup
uri.Query["key"] = "7XXUJWCWYTMXKN3L";
int sensorValue = 347;
uri.Query["field1"] = String(sensorValue);
REQUIRE(uri.toString() == FS_url);
REQUIRE_EQ(uri.toString(), FS_url);
REQUIRE(!uri.Scheme);
REQUIRE_EQ(uri.Port, 0);
REQUIRE_EQ(uri.getPort(), 80);
}
}

Expand Down
Loading