reverted HTTPCLient debug back to defaulted off
Fork of HTTPClient-SSL by
Revision 0:2ccb9960a044, committed 2012-04-26
- Comitter:
- donatien
- Date:
- Thu Apr 26 13:04:56 2012 +0000
- Child:
- 1:b70c37cf73ca
- Commit message:
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPClient.cpp Thu Apr 26 13:04:56 2012 +0000 @@ -0,0 +1,628 @@ +/* HTTPClient.cpp */ +/* +Copyright (C) 2012 ARM Limited. + +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. +*/ + +#define __DEBUG__ 4 //Maximum verbosity +#ifndef __MODULE__ +#define __MODULE__ "HTTPClient.cpp" +#endif + +#include "core/fwk.h" + +#include "HTTPClient.h" + +#define HTTP_REQUEST_TIMEOUT 30000 +#define HTTP_PORT 80 + +#define CHUNK_SIZE 256 + +#include <cstring> + +HTTPClient::HTTPClient() : +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 + +int HTTPClient::get(const char* url, IHTTPDataIn* pDataIn, uint32_t timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking +{ + return connect(url, HTTP_GET, NULL, pDataIn, timeout); +} + +int HTTPClient::get(const char* url, char* result, size_t maxResultLen, uint32_t timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking +{ + HTTPText str(result, maxResultLen); + return get(url, &str, timeout); +} + +int HTTPClient::post(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, uint32_t timeout /*= HTTP_CLIENT_DEFAULT_TIMEOUT*/) //Blocking +{ + return connect(url, HTTP_POST, (IHTTPDataOut*)&dataOut, pDataIn, timeout); +} + +int HTTPClient::getHTTPResponseCode() +{ + return m_httpResponseCode; +} + + +int HTTPClient::connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, uint32_t timeout) //Execute request +{ + m_httpResponseCode = 0; //Invalidate code + m_timeout = timeout; + + 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?) + int ret = parseURL(url, scheme, sizeof(scheme), host, sizeof(host), &port, path, sizeof(path)); + if(ret != OK) + { + ERR("parseURL returned %d", ret); + return ret; + } + + 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); + + //Now populate structure + std::memset(&m_serverAddr, 0, sizeof(struct sockaddr_in)); + + //Resolve DNS if needed + + DBG("Resolving DNS address or populate hard-coded IP address"); + struct hostent *server = socket::gethostbyname(host); + if(server == NULL) + { + return NET_NOTFOUND; //Fail + } + memcpy((char*)&m_serverAddr.sin_addr.s_addr, (char*)server->h_addr_list[0], server->h_length); + + m_serverAddr.sin_family = AF_INET; + m_serverAddr.sin_port = htons(port); + + //Create socket + DBG("Creating socket"); + m_sock = socket::socket(AF_INET, SOCK_STREAM, 0); //UDP socket + if (m_sock < 0) + { + ERR("Could not create socket"); + return NET_OOM; + } + DBG("Handle is %d", m_sock); + + //Connect it + DBG("Connecting socket to %s:%d", inet_ntoa(m_serverAddr.sin_addr), ntohs(m_serverAddr.sin_port)); + ret = socket::connect(m_sock, (const struct sockaddr *)&m_serverAddr, sizeof(m_serverAddr)); + if (ret < 0) + { + socket::close(m_sock); + ERR("Could not connect"); + return NET_CONN; + } + + //Send request + DBG("Sending request"); + char line[128]; + const char* meth = (method==HTTP_GET)?"GET":(method==HTTP_POST)?"POST":""; + snprintf(line, sizeof(line), "%s %s HTTP/1.1\r\nHost: %s\r\n", meth, path, host); //Write request + ret = send(line); + if(ret) + { + socket::close(m_sock); + ERR("Could not write request"); + return NET_CONN; + } + + //Send all headers + + //Send default headers + DBG("Sending headers"); + if( (method == HTTP_POST) && (pDataOut != NULL) ) + { + if( pDataOut->getIsChunked() ) + { + ret = send("Transfer-Encoding: chunked\r\n"); + if(ret != OK) goto connerr; + } + else + { + snprintf(line, sizeof(line), "Content-Length: %d\r\n", pDataOut->getDataLen()); + ret = send(line); + if(ret != OK) goto connerr; + } + char type[48]; + if( pDataOut->getDataType(type, 48) == OK ) + { + snprintf(line, sizeof(line), "Content-Type: %s\r\n", type); + ret = send(line); + if(ret != OK) goto connerr; + } + } + + //Close headers + DBG("Headers sent"); + ret = send("\r\n"); + if(ret != OK) goto connerr; + + char buf[CHUNK_SIZE]; + size_t trfLen; + + //Send data (if POST) + if( (method == HTTP_POST) && (pDataOut != NULL) ) + { + DBG("Sending data"); + while(true) + { + size_t writtenLen = 0; + pDataOut->read(buf, CHUNK_SIZE, &trfLen); + if( pDataOut->getIsChunked() ) + { + //Write chunk header + snprintf(line, sizeof(line), "%X\r\n", trfLen); //In hex encoding + ret = send(line); + if(ret != OK) goto connerr; + } + else if( trfLen == 0 ) + { + break; + } + if( trfLen != 0 ) + { + ret = send(buf, trfLen); + if(ret != OK) goto connerr; + } + + if( pDataOut->getIsChunked() ) + { + ret = send("\r\n"); //Chunk-terminating CRLF + if(ret != OK) goto connerr; + } + else + { + writtenLen += trfLen; + if( writtenLen >= pDataOut->getDataLen() ) + { + break; + } + } + + if( trfLen == 0 ) + { + break; + } + } + + } + + //Receive response + DBG("Receiving response"); + ret = recv(buf, CHUNK_SIZE, CHUNK_SIZE, &trfLen); //Read n bytes + if(ret != OK) goto connerr; + + buf[trfLen] = '\0'; + + char* crlfPtr = strstr(buf, "\r\n"); + if(crlfPtr == NULL) + { + goto prtclerr; + } + + 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); + goto prtclerr; + } + + if(m_httpResponseCode != 200) + { + //Cannot match string, error + WARN("Response code %d", m_httpResponseCode); + goto prtclerr; + } + + DBG("Reading headers"); + + memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); + 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 ) + { + size_t newTrfLen; + ret = recv(buf + trfLen, 1, CHUNK_SIZE - trfLen - 1, &newTrfLen); + trfLen += newTrfLen; + buf[trfLen] = '\0'; + DBG("In buf: [%s]", buf); + if(ret != OK) goto connerr; + continue; + } + else + { + goto prtclerr; + } + } + + crlfPos = crlfPtr - buf; + + if(crlfPos == 0) //End of headers + { + DBG("Headers read"); + memmove(buf, &buf[2], trfLen - 2); + trfLen -= 2; + break; + } + + buf[crlfPos] = '\0'; + + char key[16]; + char value[16]; + + int n = sscanf(buf, "%16[^:]: %16[^\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)); + trfLen -= (crlfPos + 2); + + } + else + { + ERR("Could not parse header"); + goto prtclerr; + } + + } + + //Receive data + DBG("Receiving data"); + while(true) + { + size_t readLen = 0; + + if( recvChunked ) + { + //Read chunk header + crlfPos=0; + for(crlfPos++; crlfPos < trfLen - 2; crlfPos++) + { + if( buf[crlfPos] == '\r' && buf[crlfPos + 1] == '\n' ) + { + break; + } + } + if(crlfPos >= trfLen - 2) //Try to read more + { + if( trfLen < CHUNK_SIZE ) + { + size_t newTrfLen; + ret = recv(buf + trfLen, 0, CHUNK_SIZE - trfLen - 1, &newTrfLen); + trfLen += newTrfLen; + if(ret != OK) goto connerr; + continue; + } + else + { + goto prtclerr; + } + } + buf[crlfPos] = '\0'; + int n = sscanf(buf, "%x", &readLen); + if(n!=1) + { + ERR("Could not read chunk length"); + goto prtclerr; + } + + memmove(buf, &buf[crlfPos+2], trfLen - (crlfPos + 2)); + 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); + if(ret != OK) goto connerr; + + } + } while(readLen); + + if( recvChunked ) + { + if(trfLen < 2) + { + size_t newTrfLen; + //Read missing chars to find end of chunk + ret = recv(buf, 2 - trfLen, CHUNK_SIZE, &newTrfLen); + if(ret != OK) goto connerr; + trfLen += newTrfLen; + } + if( (buf[0] != '\r') || (buf[1] != '\n') ) + { + ERR("Format error"); + goto prtclerr; + } + memmove(buf, &buf[2], trfLen - 2); + trfLen -= 2; + } + else + { + break; + } + + } + + socket::close(m_sock); + DBG("Completed HTTP transaction"); + + return OK; + + connerr: + socket::close(m_sock); + ERR("Connection error (%d)", ret); + return NET_CONN; + + prtclerr: + socket::close(m_sock); + ERR("Protocol error"); + return NET_PROTOCOL; + +} + +int 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; + while(readLen < minLen) + { + //Wait for socket to be readable + //Creating FS set + fd_set socksSet; + FD_ZERO(&socksSet); + FD_SET(m_sock, &socksSet); + struct timeval t_val; + t_val.tv_sec = m_timeout / 1000; + t_val.tv_usec = (m_timeout - (t_val.tv_sec * 1000)) * 1000; + int ret = socket::select(FD_SETSIZE, &socksSet, NULL, NULL, &t_val); + if(ret <= 0 || !FD_ISSET(m_sock, &socksSet)) + { + WARN("Timeout"); + return NET_TIMEOUT; //Timeout + } + + ret = socket::recv(m_sock, buf + readLen, maxLen - readLen, 0); + if( ret > 0) + { + readLen += ret; + continue; + } + else if( ret == 0 ) + { + WARN("Connection was closed by server"); + return NET_CLOSED; //Connection was closed by server + } + else + { + ERR("Connection error (recv returned %d)", ret); + return NET_CONN; + } + } + *pReadLen = readLen; + DBG("Read %d bytes", readLen); + return OK; +} + +int 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; + while(writtenLen < len) + { + //Wait for socket to be writeable + //Creating FS set + fd_set socksSet; + FD_ZERO(&socksSet); + FD_SET(m_sock, &socksSet); + struct timeval t_val; + t_val.tv_sec = m_timeout / 1000; + t_val.tv_usec = (m_timeout - (t_val.tv_sec * 1000)) * 1000; + int ret = socket::select(FD_SETSIZE, NULL, &socksSet, NULL, &t_val); + if(ret <= 0 || !FD_ISSET(m_sock, &socksSet)) + { + WARN("Timeout"); + return NET_TIMEOUT; //Timeout + } + + ret = socket::send(m_sock, buf + writtenLen, len - writtenLen, 0); + if( ret > 0) + { + writtenLen += ret; + continue; + } + else if( ret == 0 ) + { + WARN("Connection was closed by server"); + return NET_CLOSED; //Connection was closed by server + } + else + { + ERR("Connection error (recv returned %d)", ret); + return NET_CONN; + } + } + DBG("Written %d bytes", writtenLen); + return OK; +} + +int 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 NET_INVALID; //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 NET_TOOSMALL; + } + 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, "%d", &port) != 1) + { + WARN("Could not find port"); + return NET_INVALID; + } + } + 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 NET_TOOSMALL; + } + 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 NET_TOOSMALL; + } + memcpy(path, pathPtr, pathLen); + path[pathLen] = '\0'; + + return OK; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPClient.h Thu Apr 26 13:04:56 2012 +0000 @@ -0,0 +1,142 @@ +/* HTTPClient.h */ +/* +Copyright (C) 2012 ARM Limited. + +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 "api/socket.h" + +#define HTTP_CLIENT_DEFAULT_TIMEOUT 4000 + +class HTTPData; + +#include "IHTTPData.h" +#include "mbed.h" + +///HTTP client results +enum HTTPResult +{ + HTTP_OK, ///<Success + 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 +}; + +/**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, NET error (<0) on failure + */ + int get(const char* url, IHTTPDataIn* pDataIn, uint32_t 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, NET error on failure + */ + int get(const char* url, char* result, size_t maxResultLen, uint32_t 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, NET error on failure + */ + int post(const char* url, const IHTTPDataOut& dataOut, IHTTPDataIn* pDataIn, uint32_t 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_HEAD + }; + + int connect(const char* url, HTTP_METH method, IHTTPDataOut* pDataOut, IHTTPDataIn* pDataIn, uint32_t timeout); //Execute request + int recv(char* buf, size_t minLen, size_t maxLen, size_t* pReadLen); //0 on success, err code on failure + int send(char* buf, size_t len = 0); //0 on success, err code on failure + int 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 + int m_sock; + uint32_t m_timeout; + + const char* m_basicAuthUser; + const char* m_basicAuthPassword; + int m_httpResponseCode; + + struct sockaddr_in m_serverAddr; + +}; + +//Including data containers here for more convenience +#include "data/HTTPText.h" +#include "data/HTTPMap.h" + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IHTTPData.h Thu Apr 26 13:04:56 2012 +0000 @@ -0,0 +1,86 @@ +/* IHTTPData.h */ +/* +Copyright (C) 2012 ARM Limited. + +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 + +///This is a simple interface for HTTP data storage (impl examples are Key/Value Pairs, File, etc...) +class IHTTPDataOut +{ +protected: + friend class HTTPClient; + + /** 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; + + /** 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/HTTPMap.cpp Thu Apr 26 13:04:56 2012 +0000 @@ -0,0 +1,198 @@ +/* HTTPMap.cpp */ +/* +Copyright (C) 2012 ARM Limited. + +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 "core/fwk.h" + +#include "HTTPMap.h" + +#include <cstring> + +#include <cctype> + +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*/ 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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/HTTPMap.h Thu Apr 26 13:04:56 2012 +0000 @@ -0,0 +1,73 @@ +/* HTTPMap.h */ +/* +Copyright (C) 2012 ARM Limited. + +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 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_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/HTTPText.cpp Thu Apr 26 13:04:56 2012 +0000 @@ -0,0 +1,92 @@ +/* HTTPText.cpp */ +/* +Copyright (C) 2012 ARM Limited. + +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 "core/fwk.h" + +#include "HTTPText.h" + +#include <cstring> + +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*/ 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*/ 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 +{ + +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/HTTPText.h Thu Apr 26 13:04:56 2012 +0000 @@ -0,0 +1,72 @@ +/* HTTPText.h */ +/* +Copyright (C) 2012 ARM Limited. + +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 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 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_ */