The code from https://github.com/vpcola/Nucleo

Committer:
sinrab
Date:
Wed Oct 08 11:00:24 2014 +0000
Revision:
0:5464d5e415e5
The code from https://github.com/vpcola/Nucleo

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sinrab 0:5464d5e415e5 1 #include "HttpClient.h"
sinrab 0:5464d5e415e5 2 #include "Utility.h"
sinrab 0:5464d5e415e5 3 #include <string>
sinrab 0:5464d5e415e5 4 #include <cstring>
sinrab 0:5464d5e415e5 5 #include <vector>
sinrab 0:5464d5e415e5 6
sinrab 0:5464d5e415e5 7 extern Serial pc;
sinrab 0:5464d5e415e5 8
sinrab 0:5464d5e415e5 9 #if 1
sinrab 0:5464d5e415e5 10 //Enable debug
sinrab 0:5464d5e415e5 11 #include <cstdio>
sinrab 0:5464d5e415e5 12 #define DBG(x, ...) pc.printf("[HTTPClient : DBG]"x"\r\n", ##__VA_ARGS__);
sinrab 0:5464d5e415e5 13 #define WARN(x, ...) pc.printf("[HTTPClient : WARN]"x"\r\n", ##__VA_ARGS__);
sinrab 0:5464d5e415e5 14 #define ERR(x, ...) pc.printf("[HTTPClient : ERR]"x"\r\n", ##__VA_ARGS__);
sinrab 0:5464d5e415e5 15 #else
sinrab 0:5464d5e415e5 16 //Disable debug
sinrab 0:5464d5e415e5 17 #define DBG(x, ...)
sinrab 0:5464d5e415e5 18 #define WARN(x, ...)
sinrab 0:5464d5e415e5 19 #define ERR(x, ...)
sinrab 0:5464d5e415e5 20 #endif
sinrab 0:5464d5e415e5 21
sinrab 0:5464d5e415e5 22
sinrab 0:5464d5e415e5 23
sinrab 0:5464d5e415e5 24
sinrab 0:5464d5e415e5 25 HttpClient::HttpClient(const char * hostname)
sinrab 0:5464d5e415e5 26 : _hostname(hostname)
sinrab 0:5464d5e415e5 27 {
sinrab 0:5464d5e415e5 28 }
sinrab 0:5464d5e415e5 29
sinrab 0:5464d5e415e5 30 int HttpClient::get(const char * url, char * buffer, size_t buf_len, HeaderInfo & hinfo, int timeout)
sinrab 0:5464d5e415e5 31 {
sinrab 0:5464d5e415e5 32 char scheme[8];
sinrab 0:5464d5e415e5 33 uint16_t port;
sinrab 0:5464d5e415e5 34 char host[32];
sinrab 0:5464d5e415e5 35 char path[64];
sinrab 0:5464d5e415e5 36
sinrab 0:5464d5e415e5 37 _timeout = timeout;
sinrab 0:5464d5e415e5 38
sinrab 0:5464d5e415e5 39 if(parse_url(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path)))
sinrab 0:5464d5e415e5 40 {
sinrab 0:5464d5e415e5 41 ERR("Error parsing URL");
sinrab 0:5464d5e415e5 42 return -1;
sinrab 0:5464d5e415e5 43 }
sinrab 0:5464d5e415e5 44
sinrab 0:5464d5e415e5 45 if(port == 0) //TODO do handle HTTPS->443
sinrab 0:5464d5e415e5 46 {
sinrab 0:5464d5e415e5 47 port = 80;
sinrab 0:5464d5e415e5 48 }
sinrab 0:5464d5e415e5 49
sinrab 0:5464d5e415e5 50 DBG("Scheme: %s", scheme);
sinrab 0:5464d5e415e5 51 DBG("Host: %s", host);
sinrab 0:5464d5e415e5 52 DBG("Port: %d", port);
sinrab 0:5464d5e415e5 53 DBG("Path: %s", path);
sinrab 0:5464d5e415e5 54
sinrab 0:5464d5e415e5 55 // Connect to server
sinrab 0:5464d5e415e5 56 int ret = m_sock.connect(host, port);
sinrab 0:5464d5e415e5 57 if (ret < 0)
sinrab 0:5464d5e415e5 58 {
sinrab 0:5464d5e415e5 59 m_sock.close();
sinrab 0:5464d5e415e5 60 ERR("Could not connect");
sinrab 0:5464d5e415e5 61 return -1;
sinrab 0:5464d5e415e5 62 }
sinrab 0:5464d5e415e5 63
sinrab 0:5464d5e415e5 64 //Send request
sinrab 0:5464d5e415e5 65 std::string req_header = build_http_headers("GET", (const char *) path);
sinrab 0:5464d5e415e5 66 ret = send((char *) req_header.c_str(), req_header.size());
sinrab 0:5464d5e415e5 67 if(ret)
sinrab 0:5464d5e415e5 68 {
sinrab 0:5464d5e415e5 69 m_sock.close();
sinrab 0:5464d5e415e5 70 ERR("Could not write request\r\n");
sinrab 0:5464d5e415e5 71 return -1;
sinrab 0:5464d5e415e5 72 }
sinrab 0:5464d5e415e5 73 // Process the response
sinrab 0:5464d5e415e5 74 // First get the header
sinrab 0:5464d5e415e5 75 DBG("Reading HTTP header ...\r\n");
sinrab 0:5464d5e415e5 76 char header_buf[512];
sinrab 0:5464d5e415e5 77 int header_line = 0, numread = 0;
sinrab 0:5464d5e415e5 78
sinrab 0:5464d5e415e5 79 do {
sinrab 0:5464d5e415e5 80 memset(header_buf, 0, sizeof(header_buf));
sinrab 0:5464d5e415e5 81 numread = recv_until(header_buf, sizeof(header_buf), '\n');
sinrab 0:5464d5e415e5 82 // remove trailing \r\n
sinrab 0:5464d5e415e5 83 std::string line(header_buf, numread);
sinrab 0:5464d5e415e5 84 line = trim(line, " \t\r\n");
sinrab 0:5464d5e415e5 85
sinrab 0:5464d5e415e5 86 DBG("Header line [%s]\r\n", line.c_str());
sinrab 0:5464d5e415e5 87 parse_headers(line, hinfo, header_line);
sinrab 0:5464d5e415e5 88 header_line++;
sinrab 0:5464d5e415e5 89 }while(numread > 2); // empty line for \r\n
sinrab 0:5464d5e415e5 90
sinrab 0:5464d5e415e5 91 // Show the header information
sinrab 0:5464d5e415e5 92 DBG("Http response: %d\r\n", hinfo.http_response);
sinrab 0:5464d5e415e5 93 DBG("Http response text: %s\r\n", hinfo.http_response_text.c_str());
sinrab 0:5464d5e415e5 94 for(std::map<std::string, std::string>::iterator it = hinfo.http_info.begin();
sinrab 0:5464d5e415e5 95 it != hinfo.http_info.end();
sinrab 0:5464d5e415e5 96 it++)
sinrab 0:5464d5e415e5 97 {
sinrab 0:5464d5e415e5 98 DBG("Key [%s] : Value [%s]\r\n", it->first.c_str(), it->second.c_str());
sinrab 0:5464d5e415e5 99 }
sinrab 0:5464d5e415e5 100
sinrab 0:5464d5e415e5 101 // Read the rest of the data based on content type
sinrab 0:5464d5e415e5 102 return read_data(hinfo, buffer, buf_len);
sinrab 0:5464d5e415e5 103
sinrab 0:5464d5e415e5 104 }
sinrab 0:5464d5e415e5 105
sinrab 0:5464d5e415e5 106 int HttpClient::read_data(HeaderInfo & hinfo, char * buffer, size_t buf_len)
sinrab 0:5464d5e415e5 107 {
sinrab 0:5464d5e415e5 108 int chunk_size = 0;
sinrab 0:5464d5e415e5 109 char tmp_buf[10]; // just for reading the \r\n values
sinrab 0:5464d5e415e5 110 char * buf_ptr = buffer;
sinrab 0:5464d5e415e5 111 int numread = 0;
sinrab 0:5464d5e415e5 112
sinrab 0:5464d5e415e5 113 m_sock.set_blocking(false, _timeout);
sinrab 0:5464d5e415e5 114 if (hinfo.http_info["Transfer-Encoding"] == "chunked")
sinrab 0:5464d5e415e5 115 {
sinrab 0:5464d5e415e5 116 do {
sinrab 0:5464d5e415e5 117 // read the chunk size
sinrab 0:5464d5e415e5 118 DBG("Reading chunk size ...\r\n");
sinrab 0:5464d5e415e5 119 if ( m_sock.receive_until(tmp_buf, 10, '\n') > 0)
sinrab 0:5464d5e415e5 120 {
sinrab 0:5464d5e415e5 121 chunk_size = strtoul(tmp_buf, NULL, 16);
sinrab 0:5464d5e415e5 122 DBG("Chunk size: %d\r\n", chunk_size);
sinrab 0:5464d5e415e5 123 }else
sinrab 0:5464d5e415e5 124 break;
sinrab 0:5464d5e415e5 125
sinrab 0:5464d5e415e5 126 if (chunk_size > 0)
sinrab 0:5464d5e415e5 127 {
sinrab 0:5464d5e415e5 128 // read one char at a time untill chunk size
sinrab 0:5464d5e415e5 129 int cur_read2 = 0;
sinrab 0:5464d5e415e5 130 do {
sinrab 0:5464d5e415e5 131 if (m_sock.receive(buf_ptr,1) < 0)
sinrab 0:5464d5e415e5 132 {
sinrab 0:5464d5e415e5 133 DBG("Error reading chunks with total read [%d]...\r\n", numread);
sinrab 0:5464d5e415e5 134 return -1;
sinrab 0:5464d5e415e5 135 }
sinrab 0:5464d5e415e5 136 cur_read2 ++;
sinrab 0:5464d5e415e5 137 buf_ptr ++;
sinrab 0:5464d5e415e5 138 }while(cur_read2 < chunk_size);
sinrab 0:5464d5e415e5 139 DBG("Read %d chunk\r\n", cur_read2);
sinrab 0:5464d5e415e5 140 }
sinrab 0:5464d5e415e5 141
sinrab 0:5464d5e415e5 142 numread += chunk_size;
sinrab 0:5464d5e415e5 143 DBG("Consuming new lines ...\r\n");
sinrab 0:5464d5e415e5 144 // Consume the next new line
sinrab 0:5464d5e415e5 145 m_sock.receive_until(tmp_buf, 10, '\n');
sinrab 0:5464d5e415e5 146
sinrab 0:5464d5e415e5 147 }while((chunk_size > 0) && ((buf_ptr - buffer) < buf_len));
sinrab 0:5464d5e415e5 148
sinrab 0:5464d5e415e5 149 }else
sinrab 0:5464d5e415e5 150 {
sinrab 0:5464d5e415e5 151 DBG("Reading complete data in one go ...\r\n");
sinrab 0:5464d5e415e5 152 numread = m_sock.receive_all(buffer, buf_len);
sinrab 0:5464d5e415e5 153 }
sinrab 0:5464d5e415e5 154
sinrab 0:5464d5e415e5 155 DBG("Read %d bytes", numread);
sinrab 0:5464d5e415e5 156
sinrab 0:5464d5e415e5 157 // Finally close the socket
sinrab 0:5464d5e415e5 158 m_sock.close();
sinrab 0:5464d5e415e5 159
sinrab 0:5464d5e415e5 160 return numread;
sinrab 0:5464d5e415e5 161 }
sinrab 0:5464d5e415e5 162
sinrab 0:5464d5e415e5 163 int HttpClient::parse_headers(std::string header_line, HeaderInfo & hinfo, int lineno)
sinrab 0:5464d5e415e5 164 {
sinrab 0:5464d5e415e5 165 std::vector<std::string> tokens;
sinrab 0:5464d5e415e5 166 // remove the trailing \n
sinrab 0:5464d5e415e5 167
sinrab 0:5464d5e415e5 168 if (lineno == 0)
sinrab 0:5464d5e415e5 169 {
sinrab 0:5464d5e415e5 170 // Tokenize the first line using spaces
sinrab 0:5464d5e415e5 171 split(tokens, header_line, " ");
sinrab 0:5464d5e415e5 172 if (tokens.size() == 3)
sinrab 0:5464d5e415e5 173 {
sinrab 0:5464d5e415e5 174 //for(int i=0; i < tokens.size() ; i++)
sinrab 0:5464d5e415e5 175 // pc.printf("Token[%d] = [%s]\r\n", i, tokens[i].c_str());
sinrab 0:5464d5e415e5 176
sinrab 0:5464d5e415e5 177 // The second part is the http response
sinrab 0:5464d5e415e5 178 hinfo.http_response = atol(tokens[1].c_str());
sinrab 0:5464d5e415e5 179 DBG("HTTP response [%d]\r\n", hinfo.http_response);
sinrab 0:5464d5e415e5 180 hinfo.http_response_text = trim(tokens[2]);
sinrab 0:5464d5e415e5 181 DBG("HTTP text [%s]\r\n", hinfo.http_response_text.c_str());
sinrab 0:5464d5e415e5 182 }
sinrab 0:5464d5e415e5 183 }else
sinrab 0:5464d5e415e5 184 {
sinrab 0:5464d5e415e5 185
sinrab 0:5464d5e415e5 186 // Scan for key value pairs
sinrab 0:5464d5e415e5 187 split(tokens, header_line, ":");
sinrab 0:5464d5e415e5 188 if (tokens.size() == 2)
sinrab 0:5464d5e415e5 189 {
sinrab 0:5464d5e415e5 190 //for(int i=0; i < tokens.size() ; i++)
sinrab 0:5464d5e415e5 191 // pc.printf("Token[%d] = [%s]\r\n", i, tokens[i].c_str());
sinrab 0:5464d5e415e5 192
sinrab 0:5464d5e415e5 193 std::string key = trim(tokens[0]);
sinrab 0:5464d5e415e5 194 std::string value = trim(tokens[1]);
sinrab 0:5464d5e415e5 195
sinrab 0:5464d5e415e5 196 hinfo.http_info[key] = value;
sinrab 0:5464d5e415e5 197 }
sinrab 0:5464d5e415e5 198 }
sinrab 0:5464d5e415e5 199
sinrab 0:5464d5e415e5 200 return 0;
sinrab 0:5464d5e415e5 201 }
sinrab 0:5464d5e415e5 202
sinrab 0:5464d5e415e5 203 std::string HttpClient::build_http_headers(std::string type, std::string path)
sinrab 0:5464d5e415e5 204 {
sinrab 0:5464d5e415e5 205 std::string request_hdr = type + " " + path + " " + "HTTP/1.1" + "\r\n";
sinrab 0:5464d5e415e5 206 request_hdr += "Host:" + _hostname + "\r\n";
sinrab 0:5464d5e415e5 207 request_hdr += "\r\n"; // empty line terminates the header
sinrab 0:5464d5e415e5 208
sinrab 0:5464d5e415e5 209 return request_hdr;
sinrab 0:5464d5e415e5 210
sinrab 0:5464d5e415e5 211 }
sinrab 0:5464d5e415e5 212
sinrab 0:5464d5e415e5 213 int HttpClient::parse_url(const char* url, char* scheme,
sinrab 0:5464d5e415e5 214 size_t scheme_len,
sinrab 0:5464d5e415e5 215 char* host,
sinrab 0:5464d5e415e5 216 size_t host_len,
sinrab 0:5464d5e415e5 217 uint16_t* port,
sinrab 0:5464d5e415e5 218 char* path,
sinrab 0:5464d5e415e5 219 size_t path_len) //Parse URL
sinrab 0:5464d5e415e5 220 {
sinrab 0:5464d5e415e5 221 char* schemePtr = (char*) url;
sinrab 0:5464d5e415e5 222 char* hostPtr = (char*) strstr(url, "://");
sinrab 0:5464d5e415e5 223 if(hostPtr == NULL)
sinrab 0:5464d5e415e5 224 {
sinrab 0:5464d5e415e5 225 ERR("Invalid URL [%s]\r\n", url);
sinrab 0:5464d5e415e5 226 return -1; //URL is invalid
sinrab 0:5464d5e415e5 227 }
sinrab 0:5464d5e415e5 228
sinrab 0:5464d5e415e5 229 if( scheme_len < hostPtr - schemePtr + 1 ) //including NULL-terminating char
sinrab 0:5464d5e415e5 230 {
sinrab 0:5464d5e415e5 231 ERR("Scheme str is too small (%d >= %d)\r\n", scheme_len, hostPtr - schemePtr + 1);
sinrab 0:5464d5e415e5 232 return -1;
sinrab 0:5464d5e415e5 233 }
sinrab 0:5464d5e415e5 234 memcpy(scheme, schemePtr, hostPtr - schemePtr);
sinrab 0:5464d5e415e5 235 scheme[hostPtr - schemePtr] = '\0';
sinrab 0:5464d5e415e5 236
sinrab 0:5464d5e415e5 237 hostPtr+=3;
sinrab 0:5464d5e415e5 238
sinrab 0:5464d5e415e5 239 size_t hostLen = 0;
sinrab 0:5464d5e415e5 240
sinrab 0:5464d5e415e5 241 char* portPtr = strchr(hostPtr, ':');
sinrab 0:5464d5e415e5 242 if( portPtr != NULL )
sinrab 0:5464d5e415e5 243 {
sinrab 0:5464d5e415e5 244 hostLen = portPtr - hostPtr;
sinrab 0:5464d5e415e5 245 portPtr++;
sinrab 0:5464d5e415e5 246 if( sscanf(portPtr, "%hu", port) != 1)
sinrab 0:5464d5e415e5 247 {
sinrab 0:5464d5e415e5 248 ERR("Could not find port\r\n");
sinrab 0:5464d5e415e5 249 return -1;
sinrab 0:5464d5e415e5 250 }
sinrab 0:5464d5e415e5 251 }
sinrab 0:5464d5e415e5 252 else
sinrab 0:5464d5e415e5 253 {
sinrab 0:5464d5e415e5 254 *port=0;
sinrab 0:5464d5e415e5 255 }
sinrab 0:5464d5e415e5 256 char* pathPtr = strchr(hostPtr, '/');
sinrab 0:5464d5e415e5 257 if( hostLen == 0 )
sinrab 0:5464d5e415e5 258 {
sinrab 0:5464d5e415e5 259 hostLen = pathPtr - hostPtr;
sinrab 0:5464d5e415e5 260 }
sinrab 0:5464d5e415e5 261
sinrab 0:5464d5e415e5 262 if( host_len < hostLen + 1 ) //including NULL-terminating char
sinrab 0:5464d5e415e5 263 {
sinrab 0:5464d5e415e5 264 ERR("Host str is too small (%d >= %d)\r\n", host_len, hostLen + 1);
sinrab 0:5464d5e415e5 265 return -1;
sinrab 0:5464d5e415e5 266 }
sinrab 0:5464d5e415e5 267 memcpy(host, hostPtr, hostLen);
sinrab 0:5464d5e415e5 268 host[hostLen] = '\0';
sinrab 0:5464d5e415e5 269
sinrab 0:5464d5e415e5 270 size_t pathLen;
sinrab 0:5464d5e415e5 271 char* fragmentPtr = strchr(hostPtr, '#');
sinrab 0:5464d5e415e5 272 if(fragmentPtr != NULL)
sinrab 0:5464d5e415e5 273 {
sinrab 0:5464d5e415e5 274 pathLen = fragmentPtr - pathPtr;
sinrab 0:5464d5e415e5 275 }
sinrab 0:5464d5e415e5 276 else
sinrab 0:5464d5e415e5 277 {
sinrab 0:5464d5e415e5 278 pathLen = strlen(pathPtr);
sinrab 0:5464d5e415e5 279 }
sinrab 0:5464d5e415e5 280
sinrab 0:5464d5e415e5 281 if( path_len < pathLen + 1 ) //including NULL-terminating char
sinrab 0:5464d5e415e5 282 {
sinrab 0:5464d5e415e5 283 ERR("Path str is too small (%d >= %d)\r\n", path_len, pathLen + 1);
sinrab 0:5464d5e415e5 284 return -1;
sinrab 0:5464d5e415e5 285 }
sinrab 0:5464d5e415e5 286 memcpy(path, pathPtr, pathLen);
sinrab 0:5464d5e415e5 287 path[pathLen] = '\0';
sinrab 0:5464d5e415e5 288
sinrab 0:5464d5e415e5 289 return 0;
sinrab 0:5464d5e415e5 290 }
sinrab 0:5464d5e415e5 291
sinrab 0:5464d5e415e5 292 int HttpClient::recv_until(char * buf, size_t len, char term)
sinrab 0:5464d5e415e5 293 {
sinrab 0:5464d5e415e5 294 int numread = 0;
sinrab 0:5464d5e415e5 295 if(!m_sock.is_connected())
sinrab 0:5464d5e415e5 296 {
sinrab 0:5464d5e415e5 297 ERR("Connection was closed by server\r\n");
sinrab 0:5464d5e415e5 298 return -1; //Connection was closed by server
sinrab 0:5464d5e415e5 299 }
sinrab 0:5464d5e415e5 300
sinrab 0:5464d5e415e5 301 m_sock.set_blocking(false, _timeout);
sinrab 0:5464d5e415e5 302 int ret = m_sock.receive_until(buf, len, term);
sinrab 0:5464d5e415e5 303 if(ret > 0)
sinrab 0:5464d5e415e5 304 {
sinrab 0:5464d5e415e5 305 numread += ret;
sinrab 0:5464d5e415e5 306 }
sinrab 0:5464d5e415e5 307 else if( ret == 0 )
sinrab 0:5464d5e415e5 308 {
sinrab 0:5464d5e415e5 309 ERR("Connection was closed by server\r\n");
sinrab 0:5464d5e415e5 310 return -1; //Connection was closed by server
sinrab 0:5464d5e415e5 311 }
sinrab 0:5464d5e415e5 312 else
sinrab 0:5464d5e415e5 313 {
sinrab 0:5464d5e415e5 314 ERR("Connection error (recv returned %d)\r\n", ret);
sinrab 0:5464d5e415e5 315 return -1;
sinrab 0:5464d5e415e5 316 }
sinrab 0:5464d5e415e5 317
sinrab 0:5464d5e415e5 318 DBG("Received %d bytes", numread);
sinrab 0:5464d5e415e5 319 return numread;
sinrab 0:5464d5e415e5 320 }
sinrab 0:5464d5e415e5 321
sinrab 0:5464d5e415e5 322 int HttpClient::send(char* buf, size_t len) //0 on success, err code on failure
sinrab 0:5464d5e415e5 323 {
sinrab 0:5464d5e415e5 324 if(len == 0)
sinrab 0:5464d5e415e5 325 {
sinrab 0:5464d5e415e5 326 len = strlen(buf);
sinrab 0:5464d5e415e5 327 }
sinrab 0:5464d5e415e5 328 //pc.printf("Trying to write %d bytes\r\n", len);
sinrab 0:5464d5e415e5 329 size_t writtenLen = 0;
sinrab 0:5464d5e415e5 330
sinrab 0:5464d5e415e5 331 if(!m_sock.is_connected())
sinrab 0:5464d5e415e5 332 {
sinrab 0:5464d5e415e5 333 ERR("Connection was closed by server\r\n");
sinrab 0:5464d5e415e5 334 return -1; //Connection was closed by server
sinrab 0:5464d5e415e5 335 }
sinrab 0:5464d5e415e5 336
sinrab 0:5464d5e415e5 337 m_sock.set_blocking(false, _timeout);
sinrab 0:5464d5e415e5 338 int ret = m_sock.send_all(buf, len);
sinrab 0:5464d5e415e5 339 if(ret > 0)
sinrab 0:5464d5e415e5 340 {
sinrab 0:5464d5e415e5 341 writtenLen += ret;
sinrab 0:5464d5e415e5 342 }
sinrab 0:5464d5e415e5 343 else if( ret == 0 )
sinrab 0:5464d5e415e5 344 {
sinrab 0:5464d5e415e5 345 ERR("Connection was closed by server\r\n");
sinrab 0:5464d5e415e5 346 return -1; //Connection was closed by server
sinrab 0:5464d5e415e5 347 }
sinrab 0:5464d5e415e5 348 else
sinrab 0:5464d5e415e5 349 {
sinrab 0:5464d5e415e5 350 ERR("Connection error (send returned %d)\r\n", ret);
sinrab 0:5464d5e415e5 351 return -1;
sinrab 0:5464d5e415e5 352 }
sinrab 0:5464d5e415e5 353
sinrab 0:5464d5e415e5 354 DBG("Written %d bytes\r\n", writtenLen);
sinrab 0:5464d5e415e5 355 return 0;
sinrab 0:5464d5e415e5 356 }
sinrab 0:5464d5e415e5 357