A client for the SmartREST protocol from Cumulocity.
Fork of MbedSmartRest by
Revision 14:dc3f8dd5c02b, committed 2014-04-14
- Comitter:
- vwochnik
- Date:
- Mon Apr 14 11:23:50 2014 +0000
- Parent:
- 13:e76920d5e1ec
- Child:
- 15:0ce90c525e7a
- Commit message:
- fix
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPResponseFilter.cpp Mon Apr 14 11:23:50 2014 +0000 @@ -0,0 +1,110 @@ +#include "HTTPResponseFilter.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> + +const char *cExpectedStatus = "HTTP/1.* "; + +HTTPResponseFilter::HTTPResponseFilter(AbstractDataSource& source) : _source(source), _state(RESPF_STATE_INIT) +{ +} + +HTTPResponseFilter::~HTTPResponseFilter() +{ +} + +char HTTPResponseFilter::read() +{ + if (_state != RESPF_STATE_READ_HEADERS) + return 0; + return _source.read(); +} + +uint8_t HTTPResponseFilter::status() +{ + if (_state != RESPF_STATE_READ_HEADERS) + return DS_STATUS_ERROR; + return _source.status(); +} + +uint16_t HTTPResponseFilter::readStatus() +{ + uint16_t res = 0; uint8_t state = 0; char c; size_t offset = 0; uint8_t status; + + if (_state != RESPF_STATE_INIT) + return 0; + + while ((state < 3) && (((c = _source.read()) > 0) || ((status = _source.status()) == DS_STATUS_OK))) { + switch (state) { + case 0: // read expected status line + if ((cExpectedStatus[offset] != c) && (cExpectedStatus[offset] != '*')) + state = 3; + offset++; + if (offset == strlen(cExpectedStatus)) { + state = 1; + } + break; + case 1: + if (isspace(c)) + state = 2; + if (isdigit(c)) + res = (res * 10) + (c - '0'); + break; + case 2: + if (c == '\n') + state = 3; + break; + } + } + + if ((status != DS_STATUS_OK) || (state != 3)) + return 0; + + _state = RESPF_STATE_READ_STATUS; + return res; +} + +bool HTTPResponseFilter::skipHeaders() +{ + uint16_t res = 0; uint8_t state = 0; char c; size_t offset = 0; uint8_t status; + + if (_state != RESPF_STATE_READ_STATUS) + return false; + + while ((state < 3) && (((c = _source.read()) > 0) || ((status = _source.status()) == DS_STATUS_OK))) { + switch (state) { + case 0: // start of line + if (c == '\r') { + if (offset == 0) + state = 2; + else + state = 1; + } else { + offset++; + } + break; + case 1: + if (c == '\n') { + state = 0; + offset = 0; + } + break; + case 2: + if (c == '\n') + state = 3; + break; + } + } + + if ((status != DS_STATUS_OK) || (state != 3)) + return false; + + _state = RESPF_STATE_READ_HEADERS; + return true; +} + +void HTTPResponseFilter::reset() +{ + _state = RESPF_STATE_INIT; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPResponseFilter.h Mon Apr 14 11:23:50 2014 +0000 @@ -0,0 +1,35 @@ +#ifndef HTTPRESPONSEFILTER_H +#define HTTPRESPONSEFILTER_H + +#include <stddef.h> +#include "AbstractDataSource.h" + +#define RESPF_STATE_INIT 0 +#define RESPF_STATE_READ_STATUS 1 +#define RESPF_STATE_READ_HEADERS 2 + +/** + * Reads and evaluates a HTTP response. + * The read() and status() methods allow access to the response content + * without HTTP headers. + */ +class HTTPResponseFilter : public AbstractDataSource +{ +public: + HTTPResponseFilter(AbstractDataSource& source); + ~HTTPResponseFilter(); + + char read(); + uint8_t status(); + + uint16_t readStatus(); + bool skipHeaders(); + + void reset(); + +private: + AbstractDataSource& _source; + uint8_t _state; +}; + +#endif \ No newline at end of file
--- a/MbedClient.cpp Fri Apr 11 09:33:45 2014 +0000 +++ b/MbedClient.cpp Mon Apr 14 11:23:50 2014 +0000 @@ -1,14 +1,11 @@ #include "MbedClient.h" #include <stdlib.h> -#include <stdio.h> #include <string.h> #include "b64.h" #include "mbed.h" -const char *cExpectedStatus = "HTTP/1.* 200 OK"; - MbedClient::MbedClient(const char* host, uint16_t port, const char* username, const char* password) - : _host(host), _port(port), _username(username), _password(password), _source(_sock), _sink(_sock), _sock() + : _host(host), _port(port), _username(username), _password(password), _filter(_source), _source(_sock), _sink(_sock), _sock() { _state = MBED_STATE_INIT; } @@ -56,19 +53,20 @@ uint8_t MbedClient::sendData(DataGenerator& generator) { - char len[8]; + size_t len; char lenstr[8]; if ((_state != MBED_STATE_IN_REQUEST) && (_state != MBED_STATE_SENT_ID)) return CLIENT_INTERNAL_ERROR; - snprintf(len, 8, "%ld", generator.writtenLength()); - + len = generator.writtenLength(); + snprintf(lenstr, 8, "%ld", len); + if ((!send("Content-Length: ")) || - (!send(len)) || + (!send(lenstr)) || (!send("\r\n\r\n"))) return CLIENT_CONNECTION_ERROR; - if (generator.writeTo(_sink) != generator.writtenLength()) { + if (generator.writeTo(_sink) != len) { stop(); return CLIENT_CONNECTION_ERROR; } @@ -99,47 +97,10 @@ uint8_t MbedClient::awaitResponse() { - int8_t state = 0; char c; size_t offset = 0; - if (_state != MBED_STATE_REQ_COMPLETE) return CLIENT_INTERNAL_ERROR; - while ((state >= 0) && (state < 20) && (((c = _source.read()) > 0) || (_source.status() == DS_STATUS_OK))) { - switch (state) { - case 0: // read expected status line - if ((cExpectedStatus[offset] != c) && (cExpectedStatus[offset] != '*')) - state = -1; - offset++; - if (offset == strlen(cExpectedStatus)) - state = 1; - break; - linebrk: - case 1: - if (c == '\n') - state = 2; - else if (c != '\r') - state = -1; - break; - case 2: - if (c == '\n') { - state = 20; - break; - } else if (c == '\r') { - break; - } else { - state = 3; - goto random; - } - random: - case 3: - if ((c == '\r') || (c == '\n')) { - state = 1; - goto linebrk; - } - } - } - - if (state != 20) { + if ((_filter.readStatus() != 200) || (!_filter.skipHeaders())) { stop(); return CLIENT_CONNECTION_ERROR; } @@ -150,7 +111,7 @@ AbstractDataSource& MbedClient::receiveData() { - return _source; + return _filter; } void MbedClient::stop() @@ -158,6 +119,7 @@ _sock.close(); _source.reset(); _sink.reset(); + _filter.reset(); _state = MBED_STATE_INIT; }
--- a/MbedClient.h Fri Apr 11 09:33:45 2014 +0000 +++ b/MbedClient.h Mon Apr 14 11:23:50 2014 +0000 @@ -6,6 +6,7 @@ #include "TCPSocketConnection.h" #include "MbedDataSource.h" #include "MbedDataSink.h" +#include "HTTPResponseFilter.h" #define MBED_STATE_INIT 0 #define MBED_STATE_IN_REQUEST 1 @@ -38,6 +39,7 @@ TCPSocketConnection _sock; MbedDataSource _source; MbedDataSink _sink; + HTTPResponseFilter _filter; }; #endif \ No newline at end of file
--- a/MbedDataSink.cpp Fri Apr 11 09:33:45 2014 +0000 +++ b/MbedDataSink.cpp Mon Apr 14 11:23:50 2014 +0000 @@ -1,7 +1,6 @@ #include "MbedDataSink.h" #include "MbedClient.h" #include <stdlib.h> -#include <stdio.h> #include <string.h> #include "mbed.h" @@ -21,7 +20,6 @@ return 0; } - putchar(c); _buf[_len++] = c; return 1; } @@ -58,7 +56,7 @@ { char str[24]; - snprintf(str, 24, "%uld", number); + snprintf(str, 24, "%lu", number); return write(str); } @@ -78,7 +76,7 @@ if (!_sock.is_connected()) return false; - + _sock.set_blocking(true); ret = _sock.send(_buf, _len);