branch with improvemnts

Fork of M2XStreamClient by AT&T M2X Team

Committer:
NetArc
Date:
Sun Sep 07 17:56:18 2014 +0000
Revision:
4:ba0d02be2835
Parent:
2:7ea7ab05f120
Child:
10:4ce9eba38dbe
no need for json underflow capture

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jb8414 0:f479e4f4db0e 1 #include "M2XStreamClient.h"
jb8414 0:f479e4f4db0e 2
jb8414 0:f479e4f4db0e 3 #include <jsonlite.h>
jb8414 0:f479e4f4db0e 4
jb8414 0:f479e4f4db0e 5 #include "StreamParseFunctions.h"
jb8414 0:f479e4f4db0e 6 #include "LocationParseFunctions.h"
jb8414 0:f479e4f4db0e 7
jb8414 0:f479e4f4db0e 8 const char* M2XStreamClient::kDefaultM2XHost = "api-m2x.att.com";
jb8414 0:f479e4f4db0e 9
jb8414 0:f479e4f4db0e 10 int print_encoded_string(Print* print, const char* str);
jb8414 0:f479e4f4db0e 11 int tolower(int ch);
jb8414 0:f479e4f4db0e 12
jb8414 0:f479e4f4db0e 13 #if defined(ARDUINO_PLATFORM) || defined(MBED_PLATFORM)
jb8414 0:f479e4f4db0e 14 int tolower(int ch)
jb8414 0:f479e4f4db0e 15 {
jb8414 0:f479e4f4db0e 16 // Arduino and mbed use ASCII table, so we can simplify the implementation
jb8414 0:f479e4f4db0e 17 if ((ch >= 'A') && (ch <= 'Z')) {
jb8414 0:f479e4f4db0e 18 return (ch + 32);
jb8414 0:f479e4f4db0e 19 }
jb8414 0:f479e4f4db0e 20 return ch;
jb8414 0:f479e4f4db0e 21 }
jb8414 0:f479e4f4db0e 22 #else
jb8414 0:f479e4f4db0e 23 // For other platform, we use libc's tolower by default
jb8414 0:f479e4f4db0e 24 #include <ctype.h>
jb8414 0:f479e4f4db0e 25 #endif
jb8414 0:f479e4f4db0e 26
jb8414 0:f479e4f4db0e 27 M2XStreamClient::M2XStreamClient(Client* client,
jb8414 0:f479e4f4db0e 28 const char* key,
jb8414 0:f479e4f4db0e 29 int case_insensitive,
jb8414 0:f479e4f4db0e 30 const char* host,
jb8414 0:f479e4f4db0e 31 int port) : _client(client),
jb8414 0:f479e4f4db0e 32 _key(key),
jb8414 0:f479e4f4db0e 33 _case_insensitive(case_insensitive),
jb8414 0:f479e4f4db0e 34 _host(host),
jb8414 0:f479e4f4db0e 35 _port(port),
jb8414 0:f479e4f4db0e 36 _null_print() {
jb8414 0:f479e4f4db0e 37 }
jb8414 0:f479e4f4db0e 38
jb8414 0:f479e4f4db0e 39 #define WRITE_QUERY_PART(client_, started_, name_, str_) { \
jb8414 0:f479e4f4db0e 40 if (str_) { \
jb8414 0:f479e4f4db0e 41 if (started_) { \
jb8414 0:f479e4f4db0e 42 (client_)->print("&"); \
jb8414 0:f479e4f4db0e 43 } else { \
jb8414 0:f479e4f4db0e 44 (client_)->print("?"); \
jb8414 0:f479e4f4db0e 45 started_ = true; \
jb8414 0:f479e4f4db0e 46 } \
jb8414 0:f479e4f4db0e 47 (client_)->print(name_ "="); \
jb8414 0:f479e4f4db0e 48 (client_)->print(str_); \
jb8414 0:f479e4f4db0e 49 } \
jb8414 0:f479e4f4db0e 50 }
jb8414 0:f479e4f4db0e 51
jb8414 0:f479e4f4db0e 52 int M2XStreamClient::fetchValues(const char* feedId, const char* streamName,
jb8414 0:f479e4f4db0e 53 stream_value_read_callback callback, void* context,
jb8414 0:f479e4f4db0e 54 const char* startTime, const char* endTime,
jb8414 0:f479e4f4db0e 55 const char* limit) {
jb8414 0:f479e4f4db0e 56 if (_client->connect(_host, _port)) {
jb8414 0:f479e4f4db0e 57 bool query_started = false;
jb8414 0:f479e4f4db0e 58
jb8414 0:f479e4f4db0e 59 DBGLN("%s", "Connected to M2X server!");
jb8414 0:f479e4f4db0e 60 _client->print("GET /v1/feeds/");
jb8414 0:f479e4f4db0e 61 print_encoded_string(_client, feedId);
jb8414 0:f479e4f4db0e 62 _client->print("/streams/");
jb8414 0:f479e4f4db0e 63 print_encoded_string(_client, streamName);
jb8414 0:f479e4f4db0e 64 _client->print("/values");
jb8414 0:f479e4f4db0e 65
jb8414 0:f479e4f4db0e 66 WRITE_QUERY_PART(_client, query_started, "start", startTime);
jb8414 0:f479e4f4db0e 67 WRITE_QUERY_PART(_client, query_started, "end", endTime);
jb8414 0:f479e4f4db0e 68 WRITE_QUERY_PART(_client, query_started, "limit", limit);
jb8414 0:f479e4f4db0e 69
jb8414 0:f479e4f4db0e 70 _client->println(" HTTP/1.0");
jb8414 0:f479e4f4db0e 71 writeHttpHeader(-1);
jb8414 0:f479e4f4db0e 72 } else {
jb8414 0:f479e4f4db0e 73 DBGLN("%s", "ERROR: Cannot connect to M2X server!");
jb8414 0:f479e4f4db0e 74 return E_NOCONNECTION;
jb8414 0:f479e4f4db0e 75 }
jb8414 0:f479e4f4db0e 76 int status = readStatusCode(false);
jb8414 0:f479e4f4db0e 77 if (status == 200) {
jb8414 0:f479e4f4db0e 78 readStreamValue(callback, context);
jb8414 0:f479e4f4db0e 79 }
jb8414 0:f479e4f4db0e 80
jb8414 0:f479e4f4db0e 81 close();
jb8414 0:f479e4f4db0e 82 return status;
jb8414 0:f479e4f4db0e 83 }
jb8414 0:f479e4f4db0e 84
jb8414 0:f479e4f4db0e 85 int M2XStreamClient::readLocation(const char* feedId,
jb8414 0:f479e4f4db0e 86 location_read_callback callback,
jb8414 0:f479e4f4db0e 87 void* context) {
jb8414 0:f479e4f4db0e 88 if (_client->connect(_host, _port)) {
jb8414 0:f479e4f4db0e 89 DBGLN("%s", "Connected to M2X server!");
jb8414 0:f479e4f4db0e 90 _client->print("GET /v1/feeds/");
jb8414 0:f479e4f4db0e 91 print_encoded_string(_client, feedId);
jb8414 0:f479e4f4db0e 92 _client->println("/location HTTP/1.0");
jb8414 0:f479e4f4db0e 93
jb8414 0:f479e4f4db0e 94 writeHttpHeader(-1);
jb8414 0:f479e4f4db0e 95 } else {
jb8414 0:f479e4f4db0e 96 DBGLN("%s", "ERROR: Cannot connect to M2X server!");
jb8414 0:f479e4f4db0e 97 return E_NOCONNECTION;
jb8414 0:f479e4f4db0e 98 }
jb8414 0:f479e4f4db0e 99 int status = readStatusCode(false);
jb8414 0:f479e4f4db0e 100 if (status == 200) {
jb8414 0:f479e4f4db0e 101 readLocation(callback, context);
jb8414 0:f479e4f4db0e 102 }
jb8414 0:f479e4f4db0e 103
jb8414 0:f479e4f4db0e 104 close();
jb8414 0:f479e4f4db0e 105 return status;
jb8414 0:f479e4f4db0e 106 }
jb8414 0:f479e4f4db0e 107
jb8414 0:f479e4f4db0e 108 // Encodes and prints string using Percent-encoding specified
jb8414 0:f479e4f4db0e 109 // in RFC 1738, Section 2.2
jb8414 0:f479e4f4db0e 110 int print_encoded_string(Print* print, const char* str) {
jb8414 0:f479e4f4db0e 111 int bytes = 0;
jb8414 0:f479e4f4db0e 112 for (int i = 0; str[i] != 0; i++) {
jb8414 0:f479e4f4db0e 113 if (((str[i] >= 'A') && (str[i] <= 'Z')) ||
jb8414 0:f479e4f4db0e 114 ((str[i] >= 'a') && (str[i] <= 'z')) ||
jb8414 0:f479e4f4db0e 115 ((str[i] >= '0') && (str[i] <= '9')) ||
jb8414 0:f479e4f4db0e 116 (str[i] == '-') || (str[i] == '_') ||
jb8414 0:f479e4f4db0e 117 (str[i] == '.') || (str[i] == '~')) {
jb8414 0:f479e4f4db0e 118 bytes += print->print(str[i]);
jb8414 0:f479e4f4db0e 119 } else {
jb8414 0:f479e4f4db0e 120 // Encode all other characters
jb8414 0:f479e4f4db0e 121 bytes += print->print('%');
jb8414 0:f479e4f4db0e 122 bytes += print->print(HEX(str[i] / 16));
jb8414 0:f479e4f4db0e 123 bytes += print->print(HEX(str[i] % 16));
jb8414 0:f479e4f4db0e 124 }
jb8414 0:f479e4f4db0e 125 }
jb8414 0:f479e4f4db0e 126 return bytes;
jb8414 0:f479e4f4db0e 127 }
jb8414 0:f479e4f4db0e 128
jb8414 0:f479e4f4db0e 129 void M2XStreamClient::writePostHeader(const char* feedId,
jb8414 0:f479e4f4db0e 130 const char* streamName,
jb8414 0:f479e4f4db0e 131 int contentLength) {
jb8414 0:f479e4f4db0e 132 _client->print("PUT /v1/feeds/");
jb8414 0:f479e4f4db0e 133 print_encoded_string(_client, feedId);
jb8414 0:f479e4f4db0e 134 _client->print("/streams/");
jb8414 0:f479e4f4db0e 135 print_encoded_string(_client, streamName);
jb8414 0:f479e4f4db0e 136 _client->println(" HTTP/1.0");
jb8414 0:f479e4f4db0e 137
jb8414 0:f479e4f4db0e 138 writeHttpHeader(contentLength);
jb8414 0:f479e4f4db0e 139 }
jb8414 0:f479e4f4db0e 140
jb8414 0:f479e4f4db0e 141 void M2XStreamClient::writeHttpHeader(int contentLength) {
jb8414 0:f479e4f4db0e 142 _client->println(USER_AGENT);
jb8414 0:f479e4f4db0e 143 _client->print("X-M2X-KEY: ");
jb8414 0:f479e4f4db0e 144 _client->println(_key);
jb8414 0:f479e4f4db0e 145
jb8414 0:f479e4f4db0e 146 _client->print("Host: ");
jb8414 0:f479e4f4db0e 147 print_encoded_string(_client, _host);
jb8414 0:f479e4f4db0e 148 if (_port != kDefaultM2XPort) {
jb8414 0:f479e4f4db0e 149 _client->print(":");
jb8414 0:f479e4f4db0e 150 // port is an integer, does not need encoding
jb8414 0:f479e4f4db0e 151 _client->print(_port);
jb8414 0:f479e4f4db0e 152 }
jb8414 0:f479e4f4db0e 153 _client->println();
jb8414 0:f479e4f4db0e 154
jb8414 0:f479e4f4db0e 155 if (contentLength > 0) {
jb8414 0:f479e4f4db0e 156 _client->println("Content-Type: application/json");
jb8414 0:f479e4f4db0e 157 DBG("%s", "Content Length: ");
jb8414 0:f479e4f4db0e 158 DBGLN("%d", contentLength);
jb8414 0:f479e4f4db0e 159
jb8414 0:f479e4f4db0e 160 _client->print("Content-Length: ");
jb8414 0:f479e4f4db0e 161 _client->println(contentLength);
jb8414 0:f479e4f4db0e 162 }
jb8414 0:f479e4f4db0e 163 _client->println();
jb8414 0:f479e4f4db0e 164 }
jb8414 0:f479e4f4db0e 165
jb8414 0:f479e4f4db0e 166 int M2XStreamClient::waitForString(const char* str) {
jb8414 0:f479e4f4db0e 167 int currentIndex = 0;
jb8414 0:f479e4f4db0e 168 if (str[currentIndex] == '\0') return E_OK;
jb8414 0:f479e4f4db0e 169
jb8414 0:f479e4f4db0e 170 while (true) {
jb8414 0:f479e4f4db0e 171 while (_client->available()) {
jb8414 0:f479e4f4db0e 172 char c = _client->read();
jb8414 0:f479e4f4db0e 173 DBG("%c", c);
jb8414 0:f479e4f4db0e 174
jb8414 0:f479e4f4db0e 175 int cmp;
jb8414 0:f479e4f4db0e 176 if (_case_insensitive) {
jb8414 0:f479e4f4db0e 177 cmp = tolower(c) - tolower(str[currentIndex]);
jb8414 0:f479e4f4db0e 178 } else {
jb8414 0:f479e4f4db0e 179 cmp = c - str[currentIndex];
jb8414 0:f479e4f4db0e 180 }
jb8414 0:f479e4f4db0e 181
jb8414 0:f479e4f4db0e 182 if ((str[currentIndex] == '*') || (cmp == 0)) {
jb8414 0:f479e4f4db0e 183 currentIndex++;
jb8414 0:f479e4f4db0e 184 if (str[currentIndex] == '\0') {
jb8414 0:f479e4f4db0e 185 return E_OK;
jb8414 0:f479e4f4db0e 186 }
jb8414 0:f479e4f4db0e 187 } else {
jb8414 0:f479e4f4db0e 188 // start from the beginning
jb8414 0:f479e4f4db0e 189 currentIndex = 0;
jb8414 0:f479e4f4db0e 190 }
jb8414 0:f479e4f4db0e 191 }
jb8414 0:f479e4f4db0e 192
jb8414 0:f479e4f4db0e 193 if (!_client->connected()) {
jb8414 0:f479e4f4db0e 194 DBGLN("%s", "ERROR: The client is disconnected from the server!");
jb8414 0:f479e4f4db0e 195
jb8414 0:f479e4f4db0e 196 close();
jb8414 0:f479e4f4db0e 197 return E_DISCONNECTED;
jb8414 0:f479e4f4db0e 198 }
jb8414 0:f479e4f4db0e 199
jb8414 0:f479e4f4db0e 200 delay(1000);
jb8414 0:f479e4f4db0e 201 }
jb8414 0:f479e4f4db0e 202 // never reached here
jb8414 0:f479e4f4db0e 203 return E_NOTREACHABLE;
jb8414 0:f479e4f4db0e 204 }
jb8414 0:f479e4f4db0e 205
jb8414 0:f479e4f4db0e 206 int M2XStreamClient::readStatusCode(bool closeClient) {
jb8414 0:f479e4f4db0e 207 int responseCode = 0;
jb8414 0:f479e4f4db0e 208 int ret = waitForString("HTTP/*.* ");
jb8414 0:f479e4f4db0e 209 if (ret != E_OK) {
jb8414 0:f479e4f4db0e 210 if (closeClient) close();
jb8414 0:f479e4f4db0e 211 return ret;
jb8414 0:f479e4f4db0e 212 }
jb8414 0:f479e4f4db0e 213
jb8414 0:f479e4f4db0e 214 // ret is not needed from here(since it must be E_OK), so we can use it
jb8414 0:f479e4f4db0e 215 // as a regular variable now.
jb8414 0:f479e4f4db0e 216 ret = 0;
jb8414 0:f479e4f4db0e 217 while (true) {
jb8414 0:f479e4f4db0e 218 while (_client->available()) {
jb8414 0:f479e4f4db0e 219 char c = _client->read();
jb8414 0:f479e4f4db0e 220 DBG("%c", c);
jb8414 0:f479e4f4db0e 221
jb8414 0:f479e4f4db0e 222 responseCode = responseCode * 10 + (c - '0');
jb8414 0:f479e4f4db0e 223 ret++;
jb8414 0:f479e4f4db0e 224 if (ret == 3) {
jb8414 0:f479e4f4db0e 225 if (closeClient) close();
jb8414 0:f479e4f4db0e 226 return responseCode;
jb8414 0:f479e4f4db0e 227 }
jb8414 0:f479e4f4db0e 228 }
jb8414 0:f479e4f4db0e 229
jb8414 0:f479e4f4db0e 230 if (!_client->connected()) {
jb8414 0:f479e4f4db0e 231 DBGLN("%s", "ERROR: The client is disconnected from the server!");
jb8414 0:f479e4f4db0e 232
jb8414 0:f479e4f4db0e 233 if (closeClient) close();
jb8414 0:f479e4f4db0e 234 return E_DISCONNECTED;
jb8414 0:f479e4f4db0e 235 }
jb8414 0:f479e4f4db0e 236
jb8414 0:f479e4f4db0e 237 delay(1000);
jb8414 0:f479e4f4db0e 238 }
jb8414 0:f479e4f4db0e 239
jb8414 0:f479e4f4db0e 240 // never reached here
jb8414 0:f479e4f4db0e 241 return E_NOTREACHABLE;
jb8414 0:f479e4f4db0e 242 }
jb8414 0:f479e4f4db0e 243
jb8414 0:f479e4f4db0e 244 int M2XStreamClient::readContentLength() {
jb8414 0:f479e4f4db0e 245 int ret = waitForString("Content-Length: ");
jb8414 0:f479e4f4db0e 246 if (ret != E_OK) {
jb8414 0:f479e4f4db0e 247 return ret;
jb8414 0:f479e4f4db0e 248 }
jb8414 0:f479e4f4db0e 249
jb8414 0:f479e4f4db0e 250 // From now on, ret is not needed, we can use it
jb8414 0:f479e4f4db0e 251 // to keep the final result
jb8414 0:f479e4f4db0e 252 ret = 0;
jb8414 0:f479e4f4db0e 253 while (true) {
jb8414 0:f479e4f4db0e 254 while (_client->available()) {
jb8414 0:f479e4f4db0e 255 char c = _client->read();
jb8414 0:f479e4f4db0e 256 DBG("%c", c);
jb8414 0:f479e4f4db0e 257
jb8414 0:f479e4f4db0e 258 if ((c == '\r') || (c == '\n')) {
jb8414 0:f479e4f4db0e 259 return (ret == 0) ? (E_INVALID) : (ret);
jb8414 0:f479e4f4db0e 260 } else {
jb8414 0:f479e4f4db0e 261 ret = ret * 10 + (c - '0');
jb8414 0:f479e4f4db0e 262 }
jb8414 0:f479e4f4db0e 263 }
jb8414 0:f479e4f4db0e 264
jb8414 0:f479e4f4db0e 265 if (!_client->connected()) {
jb8414 0:f479e4f4db0e 266 DBGLN("%s", "ERROR: The client is disconnected from the server!");
jb8414 0:f479e4f4db0e 267
jb8414 0:f479e4f4db0e 268 return E_DISCONNECTED;
jb8414 0:f479e4f4db0e 269 }
jb8414 0:f479e4f4db0e 270
jb8414 0:f479e4f4db0e 271 delay(1000);
jb8414 0:f479e4f4db0e 272 }
jb8414 0:f479e4f4db0e 273
jb8414 0:f479e4f4db0e 274 // never reached here
jb8414 0:f479e4f4db0e 275 return E_NOTREACHABLE;
jb8414 0:f479e4f4db0e 276 }
jb8414 0:f479e4f4db0e 277
jb8414 0:f479e4f4db0e 278 int M2XStreamClient::skipHttpHeader() {
jb8414 0:f479e4f4db0e 279 return waitForString("\r\n\r\n");
jb8414 0:f479e4f4db0e 280 }
jb8414 0:f479e4f4db0e 281
jb8414 0:f479e4f4db0e 282 void M2XStreamClient::close() {
jb8414 0:f479e4f4db0e 283 // Eats up buffered data before closing
jb8414 0:f479e4f4db0e 284 _client->flush();
jb8414 0:f479e4f4db0e 285 _client->stop();
jb8414 0:f479e4f4db0e 286 }
jb8414 0:f479e4f4db0e 287
jb8414 0:f479e4f4db0e 288 int M2XStreamClient::readStreamValue(stream_value_read_callback callback,
jb8414 0:f479e4f4db0e 289 void* context) {
NetArc 2:7ea7ab05f120 290 const int BUF_LEN = 64;
jb8414 0:f479e4f4db0e 291 char buf[BUF_LEN];
jb8414 0:f479e4f4db0e 292
jb8414 0:f479e4f4db0e 293 int length = readContentLength();
jb8414 0:f479e4f4db0e 294 if (length < 0) {
jb8414 0:f479e4f4db0e 295 close();
jb8414 0:f479e4f4db0e 296 return length;
jb8414 0:f479e4f4db0e 297 }
jb8414 0:f479e4f4db0e 298
jb8414 0:f479e4f4db0e 299 int index = skipHttpHeader();
jb8414 0:f479e4f4db0e 300 if (index != E_OK) {
jb8414 0:f479e4f4db0e 301 close();
jb8414 0:f479e4f4db0e 302 return index;
jb8414 0:f479e4f4db0e 303 }
jb8414 0:f479e4f4db0e 304 index = 0;
jb8414 0:f479e4f4db0e 305
jb8414 0:f479e4f4db0e 306 stream_parsing_context_state state;
jb8414 0:f479e4f4db0e 307 state.state = state.index = 0;
jb8414 0:f479e4f4db0e 308 state.callback = callback;
jb8414 0:f479e4f4db0e 309 state.context = context;
jb8414 0:f479e4f4db0e 310
jb8414 0:f479e4f4db0e 311 jsonlite_parser_callbacks cbs = jsonlite_default_callbacks;
jb8414 0:f479e4f4db0e 312 cbs.key_found = on_stream_key_found;
jb8414 0:f479e4f4db0e 313 cbs.string_found = on_stream_string_found;
NetArc 2:7ea7ab05f120 314 cbs.number_found = on_stream_string_found;
jb8414 0:f479e4f4db0e 315 cbs.context.client_state = &state;
jb8414 0:f479e4f4db0e 316
jb8414 0:f479e4f4db0e 317 jsonlite_parser p = jsonlite_parser_init(jsonlite_parser_estimate_size(5));
jb8414 0:f479e4f4db0e 318 jsonlite_parser_set_callback(p, &cbs);
jb8414 0:f479e4f4db0e 319
jb8414 0:f479e4f4db0e 320 jsonlite_result result = jsonlite_result_unknown;
jb8414 0:f479e4f4db0e 321 while (index < length) {
jb8414 0:f479e4f4db0e 322 int i = 0;
jb8414 0:f479e4f4db0e 323 DBG("%s", "Received Data: ");
jb8414 0:f479e4f4db0e 324 while ((i < BUF_LEN) && _client->available()) {
jb8414 0:f479e4f4db0e 325 buf[i++] = _client->read();
jb8414 0:f479e4f4db0e 326 DBG("%c", buf[i - 1]);
jb8414 0:f479e4f4db0e 327 }
jb8414 0:f479e4f4db0e 328 DBGLNEND;
jb8414 0:f479e4f4db0e 329
jb8414 0:f479e4f4db0e 330 if ((!_client->connected()) &&
jb8414 0:f479e4f4db0e 331 (!_client->available()) &&
jb8414 0:f479e4f4db0e 332 ((index + i) < length)) {
jb8414 0:f479e4f4db0e 333 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 334 close();
jb8414 0:f479e4f4db0e 335 return E_NOCONNECTION;
jb8414 0:f479e4f4db0e 336 }
jb8414 0:f479e4f4db0e 337
jb8414 0:f479e4f4db0e 338 result = jsonlite_parser_tokenize(p, buf, i);
jb8414 0:f479e4f4db0e 339 if ((result != jsonlite_result_ok) &&
jb8414 0:f479e4f4db0e 340 (result != jsonlite_result_end_of_stream)) {
jb8414 0:f479e4f4db0e 341 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 342 close();
jb8414 0:f479e4f4db0e 343 return E_JSON_INVALID;
jb8414 0:f479e4f4db0e 344 }
NetArc 2:7ea7ab05f120 345
NetArc 4:ba0d02be2835 346 index += i;
jb8414 0:f479e4f4db0e 347 }
jb8414 0:f479e4f4db0e 348
jb8414 0:f479e4f4db0e 349 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 350 close();
jb8414 0:f479e4f4db0e 351 return (result == jsonlite_result_ok) ? (E_OK) : (E_JSON_INVALID);
jb8414 0:f479e4f4db0e 352 }
jb8414 0:f479e4f4db0e 353
jb8414 0:f479e4f4db0e 354 int M2XStreamClient::readLocation(location_read_callback callback,
jb8414 0:f479e4f4db0e 355 void* context) {
jb8414 0:f479e4f4db0e 356 const int BUF_LEN = 40;
jb8414 0:f479e4f4db0e 357 char buf[BUF_LEN];
jb8414 0:f479e4f4db0e 358
jb8414 0:f479e4f4db0e 359 int length = readContentLength();
jb8414 0:f479e4f4db0e 360 if (length < 0) {
jb8414 0:f479e4f4db0e 361 close();
jb8414 0:f479e4f4db0e 362 return length;
jb8414 0:f479e4f4db0e 363 }
jb8414 0:f479e4f4db0e 364
jb8414 0:f479e4f4db0e 365 int index = skipHttpHeader();
jb8414 0:f479e4f4db0e 366 if (index != E_OK) {
jb8414 0:f479e4f4db0e 367 close();
jb8414 0:f479e4f4db0e 368 return index;
jb8414 0:f479e4f4db0e 369 }
jb8414 0:f479e4f4db0e 370 index = 0;
jb8414 0:f479e4f4db0e 371
jb8414 0:f479e4f4db0e 372 location_parsing_context_state state;
jb8414 0:f479e4f4db0e 373 state.state = state.index = 0;
jb8414 0:f479e4f4db0e 374 state.callback = callback;
jb8414 0:f479e4f4db0e 375 state.context = context;
jb8414 0:f479e4f4db0e 376
jb8414 0:f479e4f4db0e 377 jsonlite_parser_callbacks cbs = jsonlite_default_callbacks;
jb8414 0:f479e4f4db0e 378 cbs.key_found = on_location_key_found;
jb8414 0:f479e4f4db0e 379 cbs.string_found = on_location_string_found;
jb8414 0:f479e4f4db0e 380 cbs.context.client_state = &state;
jb8414 0:f479e4f4db0e 381
jb8414 0:f479e4f4db0e 382 jsonlite_parser p = jsonlite_parser_init(jsonlite_parser_estimate_size(5));
jb8414 0:f479e4f4db0e 383 jsonlite_parser_set_callback(p, &cbs);
jb8414 0:f479e4f4db0e 384
jb8414 0:f479e4f4db0e 385 jsonlite_result result = jsonlite_result_unknown;
jb8414 0:f479e4f4db0e 386 while (index < length) {
jb8414 0:f479e4f4db0e 387 int i = 0;
jb8414 0:f479e4f4db0e 388
jb8414 0:f479e4f4db0e 389 DBG("%s", "Received Data: ");
jb8414 0:f479e4f4db0e 390 while ((i < BUF_LEN) && _client->available()) {
jb8414 0:f479e4f4db0e 391 buf[i++] = _client->read();
jb8414 0:f479e4f4db0e 392 DBG("%c", buf[i - 1]);
jb8414 0:f479e4f4db0e 393 }
jb8414 0:f479e4f4db0e 394 DBGLNEND;
jb8414 0:f479e4f4db0e 395
jb8414 0:f479e4f4db0e 396 if ((!_client->connected()) &&
jb8414 0:f479e4f4db0e 397 (!_client->available()) &&
jb8414 0:f479e4f4db0e 398 ((index + i) < length)) {
jb8414 0:f479e4f4db0e 399 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 400 close();
jb8414 0:f479e4f4db0e 401 return E_NOCONNECTION;
jb8414 0:f479e4f4db0e 402 }
jb8414 0:f479e4f4db0e 403
jb8414 0:f479e4f4db0e 404 result = jsonlite_parser_tokenize(p, buf, i);
jb8414 0:f479e4f4db0e 405 if ((result != jsonlite_result_ok) &&
jb8414 0:f479e4f4db0e 406 (result != jsonlite_result_end_of_stream)) {
jb8414 0:f479e4f4db0e 407 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 408 close();
jb8414 0:f479e4f4db0e 409 return E_JSON_INVALID;
jb8414 0:f479e4f4db0e 410 }
jb8414 0:f479e4f4db0e 411
jb8414 0:f479e4f4db0e 412 index += i;
jb8414 0:f479e4f4db0e 413 }
jb8414 0:f479e4f4db0e 414
jb8414 0:f479e4f4db0e 415 jsonlite_parser_release(p);
jb8414 0:f479e4f4db0e 416 close();
jb8414 0:f479e4f4db0e 417 return (result == jsonlite_result_ok) ? (E_OK) : (E_JSON_INVALID);
jb8414 0:f479e4f4db0e 418 }