1
0
Fork 0

Squashed 'tmk_core/' changes from 7967731..b9e0ea0

b9e0ea0 Merge commit '7fa9d8bdea3773d1195b04d98fcf27cf48ddd81d' as 'tool/mbed/mbed-sdk'
7fa9d8b Squashed 'tool/mbed/mbed-sdk/' content from commit 7c21ce5

git-subtree-dir: tmk_core
git-subtree-split: b9e0ea08cb940de20b3610ecdda18e9d8cd7c552
This commit is contained in:
Jun Wako 2015-04-24 16:26:14 +09:00
parent a20ef7052c
commit 1fe4406f37
4198 changed files with 2016457 additions and 0 deletions

View file

@ -0,0 +1,649 @@
/* HTTPClient.cpp */
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
//Debug is disabled by default
#if 0
//Enable debug
#include <cstdio>
#define DBG(x, ...) std::printf("[HTTPClient : DBG]"x"\r\n", ##__VA_ARGS__);
#define WARN(x, ...) std::printf("[HTTPClient : WARN]"x"\r\n", ##__VA_ARGS__);
#define ERR(x, ...) std::printf("[HTTPClient : ERR]"x"\r\n", ##__VA_ARGS__);
#else
//Disable debug
#define DBG(x, ...)
#define WARN(x, ...)
#define ERR(x, ...)
#endif
#define HTTP_PORT 80
#define OK 0
#define MIN(x,y) (((x)<(y))?(x):(y))
#define MAX(x,y) (((x)>(y))?(x):(y))
#define CHUNK_SIZE 256
#include <cstring>
#include "HTTPClient.h"
HTTPClient::HTTPClient() :
m_sock(), m_basicAuthUser(NULL), m_basicAuthPassword(NULL), m_httpResponseCode(0)
{
}
HTTPClient::~HTTPClient()
{
}
#if 0
void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification
{
m_basicAuthUser = user;
m_basicAuthPassword = password;
}
#endif
HTTPResult HTTPClient::get(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
{
return connect(url, HTTP_GET, NULL, pDataIn, timeout);
}
HTTPResult HTTPClient::get(const char* url, char* result, size_t maxResultLen, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
{
HTTPText str(result, maxResultLen);
return get(url, &str, timeout);
}
HTTPResult HTTPClient::post(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
{
return connect(url, HTTP_POST, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
}
HTTPResult HTTPClient::put(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
{
return connect(url, HTTP_PUT, (IHTTPDataOut*)&dataOut, pDataIn, timeout);
}
HTTPResult HTTPClient::del(const char* url, IHTTPDataIn* pDataIn, int timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking
{
return connect(url, HTTP_DELETE, NULL, pDataIn, timeout);
}
int HTTPClient::getHTTPResponseCode()
{
return m_httpResponseCode;
}
#define CHECK_CONN_ERR(ret) \
do{ \
if(ret) { \
m_sock.close(); \
ERR("Connection error (%d)", ret); \
return HTTP_CONN; \
} \
} while(0)
#define PRTCL_ERR() \
do{ \
m_sock.close(); \
ERR("Protocol error"); \
return HTTP_PRTCL; \
} while(0)
HTTPResult HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout) //Execute request
{
m_httpResponseCode = 0; //Invalidate code
m_timeout = timeout;
pDataIn->writeReset();
if( pDataOut )
{
pDataOut->readReset();
}
char scheme[8];
uint16_t port;
char host[32];
char path[64];
//First we need to parse the url (http[s]://host[:port][/[path]]) -- HTTPS not supported (yet?)
HTTPResult res = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path));
if(res != HTTP_OK)
{
ERR("parseURL returned %d", res);
return res;
}
if(port == 0) //TODO do handle HTTPS->443
{
port = 80;
}
DBG("Scheme: %s", scheme);
DBG("Host: %s", host);
DBG("Port: %d", port);
DBG("Path: %s", path);
//Connect
DBG("Connecting socket to server");
int ret = m_sock.connect(host, port);
if (ret < 0)
{
m_sock.close();
ERR("Could not connect");
return HTTP_CONN;
}
//Send request
DBG("Sending request");
char buf[CHUNK_SIZE];
const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":(method==HTTP_PUT)?"PUT":(method==HTTP_DELETE)?"DELETE":"";
snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request
ret = send(buf);
if(ret)
{
m_sock.close();
ERR("Could not write request");
return HTTP_CONN;
}
//Send all headers
//Send default headers
DBG("Sending headers");
if( pDataOut != NULL )
{
if( pDataOut->getIsChunked() )
{
ret = send("Transfer-Encoding: chunked\r\n");
CHECK_CONN_ERR(ret);
}
else
{
snprintf(buf, sizeof(buf), "Content-Length: %d\r\n", pDataOut->getDataLen());
ret = send(buf);
CHECK_CONN_ERR(ret);
}
char type[48];
if( pDataOut->getDataType(type, 48) == HTTP_OK )
{
snprintf(buf, sizeof(buf), "Content-Type: %s\r\n", type);
ret = send(buf);
CHECK_CONN_ERR(ret);
}
}
//Close headers
DBG("Headers sent");
ret = send("\r\n");
CHECK_CONN_ERR(ret);
size_t trfLen;
//Send data (if available)
if( pDataOut != NULL )
{
DBG("Sending data");
while(true)
{
size_t writtenLen = 0;
pDataOut->read(buf, CHUNK_SIZE, &trfLen);
if( pDataOut->getIsChunked() )
{
//Write chunk header
char chunkHeader[16];
snprintf(chunkHeader, sizeof(chunkHeader), "%X\r\n", trfLen); //In hex encoding
ret = send(chunkHeader);
CHECK_CONN_ERR(ret);
}
else if( trfLen == 0 )
{
break;
}
if( trfLen != 0 )
{
ret = send(buf, trfLen);
CHECK_CONN_ERR(ret);
}
if( pDataOut->getIsChunked() )
{
ret = send("\r\n"); //Chunk-terminating CRLF
CHECK_CONN_ERR(ret);
}
else
{
writtenLen += trfLen;
if( writtenLen >= pDataOut->getDataLen() )
{
break;
}
}
if( trfLen == 0 )
{
break;
}
}
}
//Receive response
DBG("Receiving response");
ret = recv(buf, CHUNK_SIZE - 1, CHUNK_SIZE - 1, &trfLen); //Read n bytes
CHECK_CONN_ERR(ret);
buf[trfLen] = '\0';
char* crlfPtr = strstr(buf, "\r\n");
if(crlfPtr == NULL)
{
PRTCL_ERR();
}
int crlfPos = crlfPtr - buf;
buf[crlfPos] = '\0';
//Parse HTTP response
if( sscanf(buf, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 )
{
//Cannot match string, error
ERR("Not a correct HTTP answer : %s\n", buf);
PRTCL_ERR();
}
if( (m_httpResponseCode < 200) || (m_httpResponseCode >= 300) )
{
//Did not return a 2xx code; TODO fetch headers/(&data?) anyway and implement a mean of writing/reading headers
WARN("Response code %d", m_httpResponseCode);
PRTCL_ERR();
}
DBG("Reading headers");
memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
trfLen -= (crlfPos + 2);
size_t recvContentLength = 0;
bool recvChunked = false;
//Now get headers
while( true )
{
crlfPtr = strstr(buf, "\r\n");
if(crlfPtr == NULL)
{
if( trfLen < CHUNK_SIZE - 1 )
{
size_t newTrfLen;
ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen);
trfLen += newTrfLen;
buf[trfLen] = '\0';
DBG("Read %d chars; In buf: [%s]", newTrfLen, buf);
CHECK_CONN_ERR(ret);
continue;
}
else
{
PRTCL_ERR();
}
}
crlfPos = crlfPtr - buf;
if(crlfPos == 0) //End of headers
{
DBG("Headers read");
memmove(buf, &buf[2], trfLen - 2 + 1); //Be sure to move NULL-terminating char as well
trfLen -= 2;
break;
}
buf[crlfPos] = '\0';
char key[32];
char value[32];
key[31] = '\0';
value[31] = '\0';
int n = sscanf(buf, "%31[^:]: %31[^\r\n]", key, value);
if ( n == 2 )
{
DBG("Read header : %s: %s\n", key, value);
if( !strcmp(key, "Content-Length") )
{
sscanf(value, "%d", &recvContentLength);
pDataIn->setDataLen(recvContentLength);
}
else if( !strcmp(key, "Transfer-Encoding") )
{
if( !strcmp(value, "Chunked") || !strcmp(value, "chunked") )
{
recvChunked = true;
pDataIn->setIsChunked(true);
}
}
else if( !strcmp(key, "Content-Type") )
{
pDataIn->setDataType(value);
}
memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2) + 1); //Be sure to move NULL-terminating char as well
trfLen -= (crlfPos + 2);
}
else
{
ERR("Could not parse header");
PRTCL_ERR();
}
}
//Receive data
DBG("Receiving data");
while(true)
{
size_t readLen = 0;
if( recvChunked )
{
//Read chunk header
bool foundCrlf;
do
{
foundCrlf = false;
crlfPos=0;
buf[trfLen]=0;
if(trfLen >= 2)
{
for(; crlfPos < trfLen - 2; crlfPos++)
{
if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' )
{
foundCrlf = true;
break;
}
}
}
if(!foundCrlf) //Try to read more
{
if( trfLen < CHUNK_SIZE )
{
size_t newTrfLen;
ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen);
trfLen += newTrfLen;
CHECK_CONN_ERR(ret);
continue;
}
else
{
PRTCL_ERR();
}
}
} while(!foundCrlf);
buf[crlfPos] = '\0';
int n = sscanf(buf, "%x", &readLen);
if(n!=1)
{
ERR("Could not read chunk length");
PRTCL_ERR();
}
memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); //Not need to move NULL-terminating char any more
trfLen -= (crlfPos + 2);
if( readLen == 0 )
{
//Last chunk
break;
}
}
else
{
readLen = recvContentLength;
}
DBG("Retrieving %d bytes", readLen);
do
{
pDataIn->write(buf, MIN(trfLen, readLen));
if( trfLen > readLen )
{
memmove(buf, &buf[readLen], trfLen - readLen);
trfLen -= readLen;
readLen = 0;
}
else
{
readLen -= trfLen;
}
if(readLen)
{
ret = recv(buf, 1, CHUNK_SIZE - trfLen - 1, &trfLen);
CHECK_CONN_ERR(ret);
}
} while(readLen);
if( recvChunked )
{
if(trfLen < 2)
{
size_t newTrfLen;
//Read missing chars to find end of chunk
ret = recv(buf + trfLen, 2 - trfLen, CHUNK_SIZE - trfLen - 1, &newTrfLen);
CHECK_CONN_ERR(ret);
trfLen += newTrfLen;
}
if( (buf[0] != '\r') || (buf[1] != '\n') )
{
ERR("Format error");
PRTCL_ERR();
}
memmove(buf, &buf[2], trfLen - 2);
trfLen -= 2;
}
else
{
break;
}
}
m_sock.close();
DBG("Completed HTTP transaction");
return HTTP_OK;
}
HTTPResult HTTPClient::recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen) //0 on success, err code on failure
{
DBG("Trying to read between %d and %d bytes", minLen, maxLen);
size_t readLen = 0;
if(!m_sock.is_connected())
{
WARN("Connection was closed by server");
return HTTP_CLOSED; //Connection was closed by server
}
int ret;
while(readLen < maxLen)
{
if(readLen < minLen)
{
DBG("Trying to read at most %d bytes [Blocking]", minLen - readLen);
m_sock.set_blocking(false, m_timeout);
ret = m_sock.receive_all(buf + readLen, minLen - readLen);
}
else
{
DBG("Trying to read at most %d bytes [Not blocking]", maxLen - readLen);
m_sock.set_blocking(false, 0);
ret = m_sock.receive(buf + readLen, maxLen - readLen);
}
if( ret > 0)
{
readLen += ret;
}
else if( ret == 0 )
{
break;
}
else
{
if(!m_sock.is_connected())
{
ERR("Connection error (recv returned %d)", ret);
*pReadLen = readLen;
return HTTP_CONN;
}
else
{
break;
}
}
if(!m_sock.is_connected())
{
break;
}
}
DBG("Read %d bytes", readLen);
*pReadLen = readLen;
return HTTP_OK;
}
HTTPResult HTTPClient::send(char* buf, size_t len) //0 on success, err code on failure
{
if(len == 0)
{
len = strlen(buf);
}
DBG("Trying to write %d bytes", len);
size_t writtenLen = 0;
if(!m_sock.is_connected())
{
WARN("Connection was closed by server");
return HTTP_CLOSED; //Connection was closed by server
}
m_sock.set_blocking(false, m_timeout);
int ret = m_sock.send_all(buf, len);
if(ret > 0)
{
writtenLen += ret;
}
else if( ret == 0 )
{
WARN("Connection was closed by server");
return HTTP_CLOSED; //Connection was closed by server
}
else
{
ERR("Connection error (send returned %d)", ret);
return HTTP_CONN;
}
DBG("Written %d bytes", writtenLen);
return HTTP_OK;
}
HTTPResult HTTPClient::parseURL(const char* url, char* scheme, size_t maxSchemeLen, char* host, size_t maxHostLen, uint16_t* port, char* path, size_t maxPathLen) //Parse URL
{
char* schemePtr = (char*) url;
char* hostPtr = (char*) strstr(url, "://");
if(hostPtr == NULL)
{
WARN("Could not find host");
return HTTP_PARSE; //URL is invalid
}
if( maxSchemeLen < hostPtr - schemePtr + 1 ) //including NULL-terminating char
{
WARN("Scheme str is too small (%d >= %d)", maxSchemeLen, hostPtr - schemePtr + 1);
return HTTP_PARSE;
}
memcpy(scheme, schemePtr, hostPtr - schemePtr);
scheme[hostPtr - schemePtr] = '\0';
hostPtr+=3;
size_t hostLen = 0;
char* portPtr = strchr(hostPtr, ':');
if( portPtr != NULL )
{
hostLen = portPtr - hostPtr;
portPtr++;
if( sscanf(portPtr, "%hu", port) != 1)
{
WARN("Could not find port");
return HTTP_PARSE;
}
}
else
{
*port=0;
}
char* pathPtr = strchr(hostPtr, '/');
if( hostLen == 0 )
{
hostLen = pathPtr - hostPtr;
}
if( maxHostLen < hostLen + 1 ) //including NULL-terminating char
{
WARN("Host str is too small (%d >= %d)", maxHostLen, hostLen + 1);
return HTTP_PARSE;
}
memcpy(host, hostPtr, hostLen);
host[hostLen] = '\0';
size_t pathLen;
char* fragmentPtr = strchr(hostPtr, '#');
if(fragmentPtr != NULL)
{
pathLen = fragmentPtr - pathPtr;
}
else
{
pathLen = strlen(pathPtr);
}
if( maxPathLen < pathLen + 1 ) //including NULL-terminating char
{
WARN("Path str is too small (%d >= %d)", maxPathLen, pathLen + 1);
return HTTP_PARSE;
}
memcpy(path, pathPtr, pathLen);
path[pathLen] = '\0';
return HTTP_OK;
}

View file

@ -0,0 +1,159 @@
/* HTTPClient.h */
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/** \file
HTTP Client header file
*/
#ifndef HTTP_CLIENT_H
#define HTTP_CLIENT_H
#include "TCPSocketConnection.h"
#define HTTP_CLIENT_DEFAULT_TIMEOUT 15000
class HTTPData;
#include "IHTTPData.h"
#include "mbed.h"
///HTTP client results
enum HTTPResult
{
HTTP_PROCESSING, ///<Processing
HTTP_PARSE, ///<url Parse error
HTTP_DNS, ///<Could not resolve name
HTTP_PRTCL, ///<Protocol error
HTTP_NOTFOUND, ///<HTTP 404 Error
HTTP_REFUSED, ///<HTTP 403 Error
HTTP_ERROR, ///<HTTP xxx error
HTTP_TIMEOUT, ///<Connection timeout
HTTP_CONN, ///<Connection error
HTTP_CLOSED, ///<Connection was closed by remote host
HTTP_OK = 0, ///<Success
};
/**A simple HTTP Client
The HTTPClient is composed of:
- The actual client (HTTPClient)
- Classes that act as a data repository, each of which deriving from the HTTPData class (HTTPText for short text content, HTTPFile for file I/O, HTTPMap for key/value pairs, and HTTPStream for streaming purposes)
*/
class HTTPClient
{
public:
///Instantiate the HTTP client
HTTPClient();
~HTTPClient();
#if 0 //TODO add header handlers
/**
Provides a basic authentification feature (Base64 encoded username and password)
Pass two NULL pointers to switch back to no authentication
@param user username to use for authentication, must remain valid durlng the whole HTTP session
@param user password to use for authentication, must remain valid durlng the whole HTTP session
*/
void basicAuth(const char* user, const char* password); //Basic Authentification
#endif
//High Level setup functions
/** Execute a GET request on the URL
Blocks until completion
@param url : url on which to execute the request
@param pDataIn : pointer to an IHTTPDataIn instance that will collect the data returned by the request, can be NULL
@param timeout waiting timeout in ms (osWaitForever for blocking function, not recommended)
@return 0 on success, HTTP error (<0) on failure
*/
HTTPResult get(const char* url, IHTTPDataIn* pDataIn, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT); //Blocking
/** Execute a GET request on the URL
Blocks until completion
This is a helper to directly get a piece of text from a HTTP result
@param url : url on which to execute the request
@param result : pointer to a char array in which the result will be stored
@param maxResultLen : length of the char array (including space for the NULL-terminating char)
@param timeout waiting timeout in ms (osWaitForever for blocking function, not recommended)
@return 0 on success, HTTP error (<0) on failure
*/
HTTPResult get(const char* url, char* result, size_t maxResultLen, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT); //Blocking
/** Execute a POST request on the URL
Blocks until completion
@param url : url on which to execute the request
@param dataOut : a IHTTPDataOut instance that contains the data that will be posted
@param pDataIn : pointer to an IHTTPDataIn instance that will collect the data returned by the request, can be NULL
@param timeout waiting timeout in ms (osWaitForever for blocking function, not recommended)
@return 0 on success, HTTP error (<0) on failure
*/
HTTPResult post(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT); //Blocking
/** Execute a PUT request on the URL
Blocks until completion
@param url : url on which to execute the request
@param dataOut : a IHTTPDataOut instance that contains the data that will be put
@param pDataIn : pointer to an IHTTPDataIn instance that will collect the data returned by the request, can be NULL
@param timeout waiting timeout in ms (osWaitForever for blocking function, not recommended)
@return 0 on success, HTTP error (<0) on failure
*/
HTTPResult put(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT); //Blocking
/** Execute a DELETE request on the URL
Blocks until completion
@param url : url on which to execute the request
@param pDataIn : pointer to an IHTTPDataIn instance that will collect the data returned by the request, can be NULL
@param timeout waiting timeout in ms (osWaitForever for blocking function, not recommended)
@return 0 on success, HTTP error (<0) on failure
*/
HTTPResult del(const char* url, IHTTPDataIn* pDataIn, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT); //Blocking
/** Get last request's HTTP response code
@return The HTTP response code of the last request
*/
int getHTTPResponseCode();
private:
enum HTTP_METH
{
HTTP_GET,
HTTP_POST,
HTTP_PUT,
HTTP_DELETE,
HTTP_HEAD
};
HTTPResult connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, int timeout); //Execute request
HTTPResult recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen); //0 on success, err code on failure
HTTPResult send(char* buf, size_t len = 0); //0 on success, err code on failure
HTTPResult parseURL(const char* url, char* scheme, size_t maxSchemeLen, char* host, size_t maxHostLen, uint16_t* port, char* path, size_t maxPathLen); //Parse URL
//Parameters
TCPSocketConnection m_sock;
int m_timeout;
const char* m_basicAuthUser;
const char* m_basicAuthPassword;
int m_httpResponseCode;
};
//Including data containers here for more convenience
#include "data/HTTPText.h"
#include "data/HTTPMap.h"
#endif

View file

@ -0,0 +1,96 @@
/* IHTTPData.h */
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef IHTTPDATA_H
#define IHTTPDATA_H
#include <cstring>
using std::size_t;
///This is a simple interface for HTTP data storage (impl examples are Key/Value Pairs, File, etc...)
class IHTTPDataOut
{
protected:
friend class HTTPClient;
/** Reset stream to its beginning
* Called by the HTTPClient on each new request
*/
virtual void readReset() = 0;
/** Read a piece of data to be transmitted
* @param buf Pointer to the buffer on which to copy the data
* @param len Length of the buffer
* @param pReadLen Pointer to the variable on which the actual copied data length will be stored
*/
virtual int read(char* buf, size_t len, size_t* pReadLen) = 0;
/** Get MIME type
* @param type Internet media type from Content-Type header
*/
virtual int getDataType(char* type, size_t maxTypeLen) = 0; //Internet media type for Content-Type header
/** Determine whether the HTTP client should chunk the data
* Used for Transfer-Encoding header
*/
virtual bool getIsChunked() = 0;
/** If the data is not chunked, get its size
* Used for Content-Length header
*/
virtual size_t getDataLen() = 0;
};
///This is a simple interface for HTTP data storage (impl examples are Key/Value Pairs, File, etc...)
class IHTTPDataIn
{
protected:
friend class HTTPClient;
/** Reset stream to its beginning
* Called by the HTTPClient on each new request
*/
virtual void writeReset() = 0;
/** Write a piece of data transmitted by the server
* @param buf Pointer to the buffer from which to copy the data
* @param len Length of the buffer
*/
virtual int write(const char* buf, size_t len) = 0;
/** Set MIME type
* @param type Internet media type from Content-Type header
*/
virtual void setDataType(const char* type) = 0;
/** Determine whether the data is chunked
* Recovered from Transfer-Encoding header
*/
virtual void setIsChunked(bool chunked) = 0;
/** If the data is not chunked, set its size
* From Content-Length header
*/
virtual void setDataLen(size_t len) = 0;
};
#endif

View file

@ -0,0 +1,200 @@
/* HTTPMap.cpp */
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "HTTPMap.h"
#include <cstring>
#include <cctype>
#define OK 0
using std::strncpy;
HTTPMap::HTTPMap() : m_pos(0), m_count(0)
{
}
void HTTPMap::put(const char* key, const char* value)
{
if(m_count >= HTTPMAP_TABLE_SIZE)
{
return;
}
m_keys[m_count] = key;
m_values[m_count] = value;
m_count++;
}
void HTTPMap::clear()
{
m_count = 0;
m_pos = 0;
}
/*virtual*/ void HTTPMap::readReset()
{
m_pos = 0;
}
/*virtual*/ int HTTPMap::read(char* buf, size_t len, size_t* pReadLen)
{
if(m_pos >= m_count)
{
*pReadLen = 0;
m_pos = 0;
return OK;
}
//URL encode
char* out = buf;
const char* in = m_keys[m_pos];
if( (m_pos != 0) && (out - buf < len - 1) )
{
*out='&';
out++;
}
while( (*in != '\0') && (out - buf < len - 3) )
{
if (std::isalnum(*in) || *in == '-' || *in == '_' || *in == '.' || *in == '~')
{
*out = *in;
out++;
}
else if( *in == ' ' )
{
*out='+';
out++;
}
else
{
char hex[] = "0123456789abcdef";
*out='%';
out++;
*out=hex[(*in>>4)&0xf];
out++;
*out=hex[(*in)&0xf];
out++;
}
in++;
}
if( out - buf < len - 1 )
{
*out='=';
out++;
}
in = m_values[m_pos];
while( (*in != '\0') && (out - buf < len - 3) )
{
if (std::isalnum(*in) || *in == '-' || *in == '_' || *in == '.' || *in == '~')
{
*out = *in;
out++;
}
else if( *in == ' ' )
{
*out='+';
out++;
}
else
{
char hex[] = "0123456789abcdef";
*out='%';
out++;
*out=hex[(*in>>4)&0xf];
out++;
*out=hex[(*in)&0xf];
out++;
}
in++;
}
*pReadLen = out - buf;
m_pos++;
return OK;
}
/*virtual*/ int HTTPMap::getDataType(char* type, size_t maxTypeLen) //Internet media type for Content-Type header
{
strncpy(type, "application/x-www-form-urlencoded", maxTypeLen-1);
type[maxTypeLen-1] = '\0';
return OK;
}
/*virtual*/ bool HTTPMap::getIsChunked() //For Transfer-Encoding header
{
return false; ////Data is computed one key/value pair at a time
}
/*virtual*/ size_t HTTPMap::getDataLen() //For Content-Length header
{
size_t count = 0;
for(size_t i = 0; i< m_count; i++)
{
//URL encode
const char* in = m_keys[i];
if( i != 0 )
{
count++;
}
while( (*in != '\0') )
{
if (std::isalnum(*in) || *in == '-' || *in == '_' || *in == '.' || *in == '~')
{
count++;
}
else if( *in == ' ' )
{
count++;
}
else
{
count+=3;
}
in++;
}
count ++;
in = m_values[i];
while( (*in != '\0') )
{
if (std::isalnum(*in) || *in == '-' || *in == '_' || *in == '.' || *in == '~')
{
count++;
}
else if( *in == ' ' )
{
count++;
}
else
{
count+=3;
}
in++;
}
}
return count;
}

View file

@ -0,0 +1,71 @@
/* HTTPMap.h */
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef HTTPMAP_H_
#define HTTPMAP_H_
#include "../IHTTPData.h"
#define HTTPMAP_TABLE_SIZE 32
/** Map of key/value pairs
* Used to transmit POST data using the application/x-www-form-urlencoded encoding
*/
class HTTPMap: public IHTTPDataOut
{
public:
/**
Instantiates HTTPMap
It supports at most 32 key/values pairs
*/
HTTPMap();
/** Put Key/Value pair
The references to the parameters must remain valid as long as the clear() function is not called
@param key The key to use
@param value The corresponding value
*/
void put(const char* key, const char* value);
/** Clear table
*/
void clear();
protected:
//IHTTPDataIn
virtual void readReset();
virtual int read(char* buf, size_t len, size_t* pReadLen);
virtual int getDataType(char* type, size_t maxTypeLen); //Internet media type for Content-Type header
virtual bool getIsChunked(); //For Transfer-Encoding header
virtual size_t getDataLen(); //For Content-Length header
private:
const char* m_keys[HTTPMAP_TABLE_SIZE];
const char* m_values[HTTPMAP_TABLE_SIZE];
size_t m_pos;
size_t m_count;
};
#endif /* HTTPMAP_H_ */

View file

@ -0,0 +1,104 @@
/* HTTPText.cpp */
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "HTTPText.h"
#include <cstring>
#define OK 0
using std::memcpy;
using std::strncpy;
using std::strlen;
#define MIN(x,y) (((x)<(y))?(x):(y))
HTTPText::HTTPText(char* str) : m_str(str), m_pos(0)
{
m_size = strlen(str) + 1;
}
HTTPText::HTTPText(char* str, size_t size) : m_str(str), m_size(size), m_pos(0)
{
}
//IHTTPDataIn
/*virtual*/ void HTTPText::readReset()
{
m_pos = 0;
}
/*virtual*/ int HTTPText::read(char* buf, size_t len, size_t* pReadLen)
{
*pReadLen = MIN(len, m_size - 1 - m_pos);
memcpy(buf, m_str + m_pos, *pReadLen);
m_pos += *pReadLen;
return OK;
}
/*virtual*/ int HTTPText::getDataType(char* type, size_t maxTypeLen) //Internet media type for Content-Type header
{
strncpy(type, "text/plain", maxTypeLen-1);
type[maxTypeLen-1] = '\0';
return OK;
}
/*virtual*/ bool HTTPText::getIsChunked() //For Transfer-Encoding header
{
return false;
}
/*virtual*/ size_t HTTPText::getDataLen() //For Content-Length header
{
return m_size - 1;
}
//IHTTPDataOut
/*virtual*/ void HTTPText::writeReset()
{
m_pos = 0;
}
/*virtual*/ int HTTPText::write(const char* buf, size_t len)
{
size_t writeLen = MIN(len, m_size - 1 - m_pos);
memcpy(m_str + m_pos, buf, writeLen);
m_pos += writeLen;
m_str[m_pos] = '\0';
return OK;
}
/*virtual*/ void HTTPText::setDataType(const char* type) //Internet media type from Content-Type header
{
}
/*virtual*/ void HTTPText::setIsChunked(bool chunked) //From Transfer-Encoding header
{
}
/*virtual*/ void HTTPText::setDataLen(size_t len) //From Content-Length header, or if the transfer is chunked, next chunk length
{
}

View file

@ -0,0 +1,72 @@
/* HTTPText.h */
/* Copyright (C) 2012 mbed.org, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef HTTPTEXT_H_
#define HTTPTEXT_H_
#include "../IHTTPData.h"
/** A data endpoint to store text
*/
class HTTPText : public IHTTPDataIn, public IHTTPDataOut
{
public:
/** Create an HTTPText instance for output
* @param str String to be transmitted
*/
HTTPText(char* str);
/** Create an HTTPText instance for input
* @param str Buffer to store the incoming string
* @param size Size of the buffer
*/
HTTPText(char* str, size_t size);
protected:
//IHTTPDataIn
virtual void readReset();
virtual int read(char* buf, size_t len, size_t* pReadLen);
virtual int getDataType(char* type, size_t maxTypeLen); //Internet media type for Content-Type header
virtual bool getIsChunked(); //For Transfer-Encoding header
virtual size_t getDataLen(); //For Content-Length header
//IHTTPDataOut
virtual void writeReset();
virtual int write(const char* buf, size_t len);
virtual void setDataType(const char* type); //Internet media type from Content-Type header
virtual void setIsChunked(bool chunked); //From Transfer-Encoding header
virtual void setDataLen(size_t len); //From Content-Length header, or if the transfer is chunked, next chunk length
private:
char* m_str;
size_t m_size;
size_t m_pos;
};
#endif /* HTTPTEXT_H_ */

View file

@ -0,0 +1,58 @@
#include "mbed.h"
#include "CellularModem.h"
#include "HTTPClient.h"
#include "httptest.h"
int httptest(CellularModem& modem, const char* apn, const char* username, const char* password)
{
printf("Connecting...\n");
HTTPClient http;
char str[512];
modem.power(true);
Thread::wait(1000);
int ret = modem.connect(apn, username, password);
if(ret)
{
printf("Could not connect\n");
return false;
}
//GET data
printf("Trying to fetch page...\n");
ret = http.get("http://mbed.org/media/uploads/donatien/hello.txt", str, 128);
if (!ret)
{
printf("Page fetched successfully - read %d characters\n", strlen(str));
printf("Result: %s\n", str);
}
else
{
printf("Error - ret = %d - HTTP return code = %d\n", ret, http.getHTTPResponseCode());
modem.disconnect();
return false;
}
//POST data
HTTPMap map;
HTTPText text(str, 512);
map.put("Hello", "World");
map.put("test", "1234");
printf("Trying to post data...\n");
ret = http.post("http://httpbin.org/post", map, &text);
if (!ret)
{
printf("Executed POST successfully - read %d characters\n", strlen(str));
printf("Result: %s\n", str);
}
else
{
printf("Error - ret = %d - HTTP return code = %d\n", ret, http.getHTTPResponseCode());
modem.disconnect();
return false;
}
modem.disconnect();
return true;
}

View file

@ -0,0 +1,9 @@
#ifndef HTTPTEST_H_
#define HTTPTEST_H_
#include "CellularModem.h"
int httptest(CellularModem& modem, const char* apn = NULL, const char* username = NULL, const char* password= NULL);
#endif

View file

@ -0,0 +1,35 @@
#include "UbloxUSBGSMModem.h"
#include "UbloxUSBCDMAModem.h"
#include "httptest.h"
#if !defined(MODEM_UBLOX_GSM) && !defined(MODEM_UBLOX_CDMA)
#warning No modem defined, using GSM by default
#define MODEM_UBLOX_GSM
#endif
#ifndef MODEM_APN
#warning APN not specified, using "internet"
#define MODEM_APN "internet"
#endif
#ifndef MODEM_USERNAME
#warning username not specified
#define MODEM_USERNAME NULL
#endif
#ifndef MODEM_PASSWORD
#warning password not specified
#define MODEM_PASSWORD NULL
#endif
int main()
{
#ifdef MODEM_UBLOX_GSM
UbloxUSBGSMModem modem;
#else
UbloxUSBCDMAModem modem(p18, true, 1);
#endif
httptest(modem, MODEM_APN, MODEM_USERNAME, MODEM_PASSWORD);
while (true);
}

View file

@ -0,0 +1,41 @@
#include "CellularModem.h"
#include "smstest.h"
void smstest(CellularModem& modem)
{
modem.power(true);
Thread::wait(1000);
#ifdef DESTINATION_NUMBER
modem.sendSM(DESINATION_NUMBER, "Hello from mbed:)");
#endif
while(true)
{
char num[17];
char msg[64];
size_t count;
int ret = modem.getSMCount(&count);
if(ret)
{
printf("getSMCount returned %d\n", ret);
Thread::wait(3000);
continue;
}
if( count > 0)
{
printf("%d SMS to read\n", count);
ret = modem.getSM(num, msg, 64);
if(ret)
{
printf("getSM returned %d\n", ret);
Thread::wait(3000);
continue;
}
printf("%s : %s\n", num, msg);
}
Thread::wait(3000);
}
}

View file

@ -0,0 +1,9 @@
#ifndef SMSTEST_H_
#define SMSTEST_H_
#include "CellularModem.h"
void smstest(CellularModem&);
#endif

View file

@ -0,0 +1,21 @@
#include "UbloxUSBGSMModem.h"
#include "UbloxUSBCDMAModem.h"
#include "smstest.h"
#if !defined(MODEM_UBLOX_GSM) && !defined(MODEM_UBLOX_CDMA)
#warning No modem defined, using GSM by default
#define MODEM_UBLOX_GSM
#endif
int main()
{
#ifdef MODEM_UBLOX_GSM
UbloxUSBGSMModem modem;
#else
UbloxUSBCDMAModem modem(p18, true, 1);
#endif
smstest(modem);
while (true);
}