![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
HTTPClient using static IP
NetServices/services/http/client/HTTPClient.cpp@0:d8f2f7d5f31b, 2011-05-30 (annotated)
- Committer:
- mr_q
- Date:
- Mon May 30 11:53:37 2011 +0000
- Revision:
- 0:d8f2f7d5f31b
v0.01 Draft
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mr_q | 0:d8f2f7d5f31b | 1 | |
mr_q | 0:d8f2f7d5f31b | 2 | /* |
mr_q | 0:d8f2f7d5f31b | 3 | Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) |
mr_q | 0:d8f2f7d5f31b | 4 | |
mr_q | 0:d8f2f7d5f31b | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy |
mr_q | 0:d8f2f7d5f31b | 6 | of this software and associated documentation files (the "Software"), to deal |
mr_q | 0:d8f2f7d5f31b | 7 | in the Software without restriction, including without limitation the rights |
mr_q | 0:d8f2f7d5f31b | 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
mr_q | 0:d8f2f7d5f31b | 9 | copies of the Software, and to permit persons to whom the Software is |
mr_q | 0:d8f2f7d5f31b | 10 | furnished to do so, subject to the following conditions: |
mr_q | 0:d8f2f7d5f31b | 11 | |
mr_q | 0:d8f2f7d5f31b | 12 | The above copyright notice and this permission notice shall be included in |
mr_q | 0:d8f2f7d5f31b | 13 | all copies or substantial portions of the Software. |
mr_q | 0:d8f2f7d5f31b | 14 | |
mr_q | 0:d8f2f7d5f31b | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
mr_q | 0:d8f2f7d5f31b | 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
mr_q | 0:d8f2f7d5f31b | 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
mr_q | 0:d8f2f7d5f31b | 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
mr_q | 0:d8f2f7d5f31b | 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
mr_q | 0:d8f2f7d5f31b | 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
mr_q | 0:d8f2f7d5f31b | 21 | THE SOFTWARE. |
mr_q | 0:d8f2f7d5f31b | 22 | */ |
mr_q | 0:d8f2f7d5f31b | 23 | |
mr_q | 0:d8f2f7d5f31b | 24 | #include "core/netservice.h" |
mr_q | 0:d8f2f7d5f31b | 25 | #include "HTTPClient.h" |
mr_q | 0:d8f2f7d5f31b | 26 | #include "../util/base64.h" |
mr_q | 0:d8f2f7d5f31b | 27 | #include "../util/url.h" |
mr_q | 0:d8f2f7d5f31b | 28 | |
mr_q | 0:d8f2f7d5f31b | 29 | //#define __DEBUG |
mr_q | 0:d8f2f7d5f31b | 30 | #include "dbg/dbg.h" |
mr_q | 0:d8f2f7d5f31b | 31 | |
mr_q | 0:d8f2f7d5f31b | 32 | #define HTTP_REQUEST_TIMEOUT 30000//15000 |
mr_q | 0:d8f2f7d5f31b | 33 | #define HTTP_PORT 80 |
mr_q | 0:d8f2f7d5f31b | 34 | |
mr_q | 0:d8f2f7d5f31b | 35 | #define CHUNK_SIZE 256 |
mr_q | 0:d8f2f7d5f31b | 36 | |
mr_q | 0:d8f2f7d5f31b | 37 | HTTPClient::HTTPClient() : NetService(false) /*Not owned by the pool*/, m_meth(HTTP_GET), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL), |
mr_q | 0:d8f2f7d5f31b | 38 | m_watchdog(), m_timeout(0), m_pDnsReq(NULL), m_server(), m_path(), |
mr_q | 0:d8f2f7d5f31b | 39 | m_closed(true), m_state(HTTP_CLOSED), |
mr_q | 0:d8f2f7d5f31b | 40 | m_pDataOut(NULL), m_pDataIn(NULL), m_dataChunked(false), m_dataPos(0), m_dataLen(0), m_httpResponseCode(0), m_blockingResult(HTTP_PROCESSING) |
mr_q | 0:d8f2f7d5f31b | 41 | |
mr_q | 0:d8f2f7d5f31b | 42 | { |
mr_q | 0:d8f2f7d5f31b | 43 | setTimeout(HTTP_REQUEST_TIMEOUT); |
mr_q | 0:d8f2f7d5f31b | 44 | m_buf = new char[CHUNK_SIZE]; |
mr_q | 0:d8f2f7d5f31b | 45 | DBG("New HTTPClient %p\n",this); |
mr_q | 0:d8f2f7d5f31b | 46 | } |
mr_q | 0:d8f2f7d5f31b | 47 | |
mr_q | 0:d8f2f7d5f31b | 48 | HTTPClient::~HTTPClient() |
mr_q | 0:d8f2f7d5f31b | 49 | { |
mr_q | 0:d8f2f7d5f31b | 50 | |
mr_q | 0:d8f2f7d5f31b | 51 | DBG("Call HTTPClient::close from ~HTTClient()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 52 | close(); |
mr_q | 0:d8f2f7d5f31b | 53 | delete[] m_buf; |
mr_q | 0:d8f2f7d5f31b | 54 | } |
mr_q | 0:d8f2f7d5f31b | 55 | |
mr_q | 0:d8f2f7d5f31b | 56 | void HTTPClient::basicAuth(const char* user, const char* password) //Basic Authentification |
mr_q | 0:d8f2f7d5f31b | 57 | { |
mr_q | 0:d8f2f7d5f31b | 58 | if(user==NULL) |
mr_q | 0:d8f2f7d5f31b | 59 | { |
mr_q | 0:d8f2f7d5f31b | 60 | m_reqHeaders.erase("Authorization"); //Remove auth str |
mr_q | 0:d8f2f7d5f31b | 61 | return; |
mr_q | 0:d8f2f7d5f31b | 62 | } |
mr_q | 0:d8f2f7d5f31b | 63 | string auth = "Basic "; |
mr_q | 0:d8f2f7d5f31b | 64 | string decStr = user; |
mr_q | 0:d8f2f7d5f31b | 65 | decStr += ":"; |
mr_q | 0:d8f2f7d5f31b | 66 | decStr += password; |
mr_q | 0:d8f2f7d5f31b | 67 | auth.append( Base64::encode(decStr) ); |
mr_q | 0:d8f2f7d5f31b | 68 | DBG("Auth str is %s\n", auth.c_str()); |
mr_q | 0:d8f2f7d5f31b | 69 | m_reqHeaders["Authorization"] = auth; |
mr_q | 0:d8f2f7d5f31b | 70 | } |
mr_q | 0:d8f2f7d5f31b | 71 | |
mr_q | 0:d8f2f7d5f31b | 72 | //High Level setup functions |
mr_q | 0:d8f2f7d5f31b | 73 | HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn) //Blocking |
mr_q | 0:d8f2f7d5f31b | 74 | { |
mr_q | 0:d8f2f7d5f31b | 75 | DBG("HTTPClient::get()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 76 | |
mr_q | 0:d8f2f7d5f31b | 77 | doGet(uri, pDataIn); |
mr_q | 0:d8f2f7d5f31b | 78 | return blockingProcess(); |
mr_q | 0:d8f2f7d5f31b | 79 | } |
mr_q | 0:d8f2f7d5f31b | 80 | |
mr_q | 0:d8f2f7d5f31b | 81 | HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn, void (*pMethod)(HTTPResult)) //Non blocking |
mr_q | 0:d8f2f7d5f31b | 82 | { |
mr_q | 0:d8f2f7d5f31b | 83 | DBG("HTTPClient::get()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 84 | |
mr_q | 0:d8f2f7d5f31b | 85 | setOnResult(pMethod); |
mr_q | 0:d8f2f7d5f31b | 86 | doGet(uri, pDataIn); |
mr_q | 0:d8f2f7d5f31b | 87 | return HTTP_PROCESSING; |
mr_q | 0:d8f2f7d5f31b | 88 | } |
mr_q | 0:d8f2f7d5f31b | 89 | |
mr_q | 0:d8f2f7d5f31b | 90 | #if 0 //For info only |
mr_q | 0:d8f2f7d5f31b | 91 | template<class T> |
mr_q | 0:d8f2f7d5f31b | 92 | HTTPResult HTTPClient::get(const char* uri, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking |
mr_q | 0:d8f2f7d5f31b | 93 | { |
mr_q | 0:d8f2f7d5f31b | 94 | DBG("HTTPClient::get()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 95 | |
mr_q | 0:d8f2f7d5f31b | 96 | setOnResult(pItem, pMethod); |
mr_q | 0:d8f2f7d5f31b | 97 | doGet(uri, pDataIn); |
mr_q | 0:d8f2f7d5f31b | 98 | return HTTP_PROCESSING; |
mr_q | 0:d8f2f7d5f31b | 99 | } |
mr_q | 0:d8f2f7d5f31b | 100 | #endif |
mr_q | 0:d8f2f7d5f31b | 101 | |
mr_q | 0:d8f2f7d5f31b | 102 | HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn) //Blocking |
mr_q | 0:d8f2f7d5f31b | 103 | { |
mr_q | 0:d8f2f7d5f31b | 104 | DBG("HTTPClient::post()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 105 | |
mr_q | 0:d8f2f7d5f31b | 106 | doPost(uri, dataOut, pDataIn); |
mr_q | 0:d8f2f7d5f31b | 107 | return blockingProcess(); |
mr_q | 0:d8f2f7d5f31b | 108 | } |
mr_q | 0:d8f2f7d5f31b | 109 | |
mr_q | 0:d8f2f7d5f31b | 110 | HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, void (*pMethod)(HTTPResult)) //Non blocking |
mr_q | 0:d8f2f7d5f31b | 111 | { |
mr_q | 0:d8f2f7d5f31b | 112 | DBG("HTTPClient::post()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 113 | |
mr_q | 0:d8f2f7d5f31b | 114 | setOnResult(pMethod); |
mr_q | 0:d8f2f7d5f31b | 115 | doPost(uri, dataOut, pDataIn); |
mr_q | 0:d8f2f7d5f31b | 116 | return HTTP_PROCESSING; |
mr_q | 0:d8f2f7d5f31b | 117 | } |
mr_q | 0:d8f2f7d5f31b | 118 | |
mr_q | 0:d8f2f7d5f31b | 119 | #if 0 //For info only |
mr_q | 0:d8f2f7d5f31b | 120 | template<class T> |
mr_q | 0:d8f2f7d5f31b | 121 | HTTPResult HTTPClient::post(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn, T* pItem, void (T::*pMethod)(HTTPResult)) //Non blocking |
mr_q | 0:d8f2f7d5f31b | 122 | { |
mr_q | 0:d8f2f7d5f31b | 123 | DBG("HTTPClient::post()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 124 | |
mr_q | 0:d8f2f7d5f31b | 125 | setOnResult(pItem, pMethod); |
mr_q | 0:d8f2f7d5f31b | 126 | doPost(uri, dataOut, pDataIn); |
mr_q | 0:d8f2f7d5f31b | 127 | return HTTP_PROCESSING; |
mr_q | 0:d8f2f7d5f31b | 128 | } |
mr_q | 0:d8f2f7d5f31b | 129 | #endif |
mr_q | 0:d8f2f7d5f31b | 130 | |
mr_q | 0:d8f2f7d5f31b | 131 | void HTTPClient::doGet(const char* uri, HTTPData* pDataIn) |
mr_q | 0:d8f2f7d5f31b | 132 | { |
mr_q | 0:d8f2f7d5f31b | 133 | DBG("HTTPClient::doGet()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 134 | |
mr_q | 0:d8f2f7d5f31b | 135 | m_meth = HTTP_GET; |
mr_q | 0:d8f2f7d5f31b | 136 | setup(uri, NULL, pDataIn); |
mr_q | 0:d8f2f7d5f31b | 137 | } |
mr_q | 0:d8f2f7d5f31b | 138 | |
mr_q | 0:d8f2f7d5f31b | 139 | void HTTPClient::doPost(const char* uri, const HTTPData& dataOut, HTTPData* pDataIn) |
mr_q | 0:d8f2f7d5f31b | 140 | { |
mr_q | 0:d8f2f7d5f31b | 141 | DBG("HTTPClient::doPost()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 142 | |
mr_q | 0:d8f2f7d5f31b | 143 | m_meth = HTTP_POST; |
mr_q | 0:d8f2f7d5f31b | 144 | setup(uri, (HTTPData*) &dataOut, pDataIn); |
mr_q | 0:d8f2f7d5f31b | 145 | } |
mr_q | 0:d8f2f7d5f31b | 146 | |
mr_q | 0:d8f2f7d5f31b | 147 | void HTTPClient::setOnResult( void (*pMethod)(HTTPResult) ) |
mr_q | 0:d8f2f7d5f31b | 148 | { |
mr_q | 0:d8f2f7d5f31b | 149 | DBG("HTTPClient::setOnResult()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 150 | |
mr_q | 0:d8f2f7d5f31b | 151 | m_pCb = pMethod; |
mr_q | 0:d8f2f7d5f31b | 152 | m_pCbItem = NULL; |
mr_q | 0:d8f2f7d5f31b | 153 | m_pCbMeth = NULL; |
mr_q | 0:d8f2f7d5f31b | 154 | } |
mr_q | 0:d8f2f7d5f31b | 155 | |
mr_q | 0:d8f2f7d5f31b | 156 | #if 0 //For info only |
mr_q | 0:d8f2f7d5f31b | 157 | template<class T> |
mr_q | 0:d8f2f7d5f31b | 158 | void HTTPClient::setOnResult( T* pItem, void (T::*pMethod)(NtpResult) ) |
mr_q | 0:d8f2f7d5f31b | 159 | { |
mr_q | 0:d8f2f7d5f31b | 160 | DBG("HTTPClient::setOnResult()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 161 | |
mr_q | 0:d8f2f7d5f31b | 162 | m_pCb = NULL; |
mr_q | 0:d8f2f7d5f31b | 163 | m_pCbItem = (CDummy*) pItem; |
mr_q | 0:d8f2f7d5f31b | 164 | m_pCbMeth = (void (CDummy::*)(NtpResult)) pMethod; |
mr_q | 0:d8f2f7d5f31b | 165 | } |
mr_q | 0:d8f2f7d5f31b | 166 | #endif |
mr_q | 0:d8f2f7d5f31b | 167 | |
mr_q | 0:d8f2f7d5f31b | 168 | void HTTPClient::setTimeout(int ms) |
mr_q | 0:d8f2f7d5f31b | 169 | { |
mr_q | 0:d8f2f7d5f31b | 170 | DBG("HTTPClient::setTimeout()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 171 | |
mr_q | 0:d8f2f7d5f31b | 172 | m_timeout = ms; |
mr_q | 0:d8f2f7d5f31b | 173 | //resetTimeout(); |
mr_q | 0:d8f2f7d5f31b | 174 | } |
mr_q | 0:d8f2f7d5f31b | 175 | |
mr_q | 0:d8f2f7d5f31b | 176 | void HTTPClient::poll() //Called by NetServices |
mr_q | 0:d8f2f7d5f31b | 177 | { |
mr_q | 0:d8f2f7d5f31b | 178 | |
mr_q | 0:d8f2f7d5f31b | 179 | if(m_closed) |
mr_q | 0:d8f2f7d5f31b | 180 | { |
mr_q | 0:d8f2f7d5f31b | 181 | return; |
mr_q | 0:d8f2f7d5f31b | 182 | } |
mr_q | 0:d8f2f7d5f31b | 183 | if(m_watchdog.read_ms()>m_timeout) |
mr_q | 0:d8f2f7d5f31b | 184 | { |
mr_q | 0:d8f2f7d5f31b | 185 | onTimeout(); |
mr_q | 0:d8f2f7d5f31b | 186 | } |
mr_q | 0:d8f2f7d5f31b | 187 | else if(m_state == HTTP_READ_DATA_INCOMPLETE) |
mr_q | 0:d8f2f7d5f31b | 188 | { |
mr_q | 0:d8f2f7d5f31b | 189 | readData(); //Try to read more data |
mr_q | 0:d8f2f7d5f31b | 190 | if( m_state == HTTP_DONE ) |
mr_q | 0:d8f2f7d5f31b | 191 | { |
mr_q | 0:d8f2f7d5f31b | 192 | //All data has been read, close w/ success :) |
mr_q | 0:d8f2f7d5f31b | 193 | DBG("Done :)!\n"); |
mr_q | 0:d8f2f7d5f31b | 194 | onResult(HTTP_OK); |
mr_q | 0:d8f2f7d5f31b | 195 | DBG("Call HTTPClient::close from HTTClient::poll()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 196 | close(); |
mr_q | 0:d8f2f7d5f31b | 197 | } |
mr_q | 0:d8f2f7d5f31b | 198 | } |
mr_q | 0:d8f2f7d5f31b | 199 | |
mr_q | 0:d8f2f7d5f31b | 200 | } |
mr_q | 0:d8f2f7d5f31b | 201 | |
mr_q | 0:d8f2f7d5f31b | 202 | int HTTPClient::getHTTPResponseCode() |
mr_q | 0:d8f2f7d5f31b | 203 | { |
mr_q | 0:d8f2f7d5f31b | 204 | DBG("HTTPClient::getHTTPResponseCode()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 205 | |
mr_q | 0:d8f2f7d5f31b | 206 | return m_httpResponseCode; |
mr_q | 0:d8f2f7d5f31b | 207 | } |
mr_q | 0:d8f2f7d5f31b | 208 | |
mr_q | 0:d8f2f7d5f31b | 209 | void HTTPClient::setRequestHeader(const string& header, const string& value) |
mr_q | 0:d8f2f7d5f31b | 210 | { |
mr_q | 0:d8f2f7d5f31b | 211 | DBG("HTTPClient::setRequestHeader()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 212 | |
mr_q | 0:d8f2f7d5f31b | 213 | m_reqHeaders[header] = value; |
mr_q | 0:d8f2f7d5f31b | 214 | } |
mr_q | 0:d8f2f7d5f31b | 215 | |
mr_q | 0:d8f2f7d5f31b | 216 | string& HTTPClient::getResponseHeader(const string& header) |
mr_q | 0:d8f2f7d5f31b | 217 | { |
mr_q | 0:d8f2f7d5f31b | 218 | DBG("HTTPClient::getResponseHeader()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 219 | |
mr_q | 0:d8f2f7d5f31b | 220 | return m_respHeaders[header]; |
mr_q | 0:d8f2f7d5f31b | 221 | } |
mr_q | 0:d8f2f7d5f31b | 222 | |
mr_q | 0:d8f2f7d5f31b | 223 | void HTTPClient::resetRequestHeaders() |
mr_q | 0:d8f2f7d5f31b | 224 | { |
mr_q | 0:d8f2f7d5f31b | 225 | DBG("HTTPClient::resetRequestHeaders()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 226 | |
mr_q | 0:d8f2f7d5f31b | 227 | m_reqHeaders.clear(); |
mr_q | 0:d8f2f7d5f31b | 228 | } |
mr_q | 0:d8f2f7d5f31b | 229 | |
mr_q | 0:d8f2f7d5f31b | 230 | void HTTPClient::resetTimeout() |
mr_q | 0:d8f2f7d5f31b | 231 | { |
mr_q | 0:d8f2f7d5f31b | 232 | DBG("HTTPClient::resetTimeout()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 233 | |
mr_q | 0:d8f2f7d5f31b | 234 | m_watchdog.reset(); |
mr_q | 0:d8f2f7d5f31b | 235 | m_watchdog.start(); |
mr_q | 0:d8f2f7d5f31b | 236 | } |
mr_q | 0:d8f2f7d5f31b | 237 | |
mr_q | 0:d8f2f7d5f31b | 238 | void HTTPClient::init() //Create and setup socket if needed |
mr_q | 0:d8f2f7d5f31b | 239 | { |
mr_q | 0:d8f2f7d5f31b | 240 | DBG("Call HTTPClient::close from HTTClient::init()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 241 | close(); //Remove previous elements |
mr_q | 0:d8f2f7d5f31b | 242 | if(!m_closed) //Already opened |
mr_q | 0:d8f2f7d5f31b | 243 | return; |
mr_q | 0:d8f2f7d5f31b | 244 | m_state = HTTP_WRITE_HEADERS; |
mr_q | 0:d8f2f7d5f31b | 245 | m_pTCPSocket = new TCPSocket; |
mr_q | 0:d8f2f7d5f31b | 246 | m_pTCPSocket->setOnEvent(this, &HTTPClient::onTCPSocketEvent); |
mr_q | 0:d8f2f7d5f31b | 247 | m_closed = false; |
mr_q | 0:d8f2f7d5f31b | 248 | m_httpResponseCode = 0; |
mr_q | 0:d8f2f7d5f31b | 249 | } |
mr_q | 0:d8f2f7d5f31b | 250 | |
mr_q | 0:d8f2f7d5f31b | 251 | void HTTPClient::close() |
mr_q | 0:d8f2f7d5f31b | 252 | { |
mr_q | 0:d8f2f7d5f31b | 253 | DBG("HTTPClient::close()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 254 | |
mr_q | 0:d8f2f7d5f31b | 255 | if(m_closed) |
mr_q | 0:d8f2f7d5f31b | 256 | return; |
mr_q | 0:d8f2f7d5f31b | 257 | m_state = HTTP_CLOSED; |
mr_q | 0:d8f2f7d5f31b | 258 | //Now Request headers are kept btw requests unless resetRequestHeaders() is called |
mr_q | 0:d8f2f7d5f31b | 259 | //m_reqHeaders.clear(); //Clear headers for next requests |
mr_q | 0:d8f2f7d5f31b | 260 | m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else |
mr_q | 0:d8f2f7d5f31b | 261 | m_watchdog.stop(); //Stop timeout |
mr_q | 0:d8f2f7d5f31b | 262 | m_watchdog.reset(); |
mr_q | 0:d8f2f7d5f31b | 263 | m_pTCPSocket->resetOnEvent(); |
mr_q | 0:d8f2f7d5f31b | 264 | m_pTCPSocket->close(); |
mr_q | 0:d8f2f7d5f31b | 265 | delete m_pTCPSocket; |
mr_q | 0:d8f2f7d5f31b | 266 | m_pTCPSocket = NULL; |
mr_q | 0:d8f2f7d5f31b | 267 | if( m_pDnsReq ) |
mr_q | 0:d8f2f7d5f31b | 268 | { |
mr_q | 0:d8f2f7d5f31b | 269 | m_pDnsReq->close(); |
mr_q | 0:d8f2f7d5f31b | 270 | delete m_pDnsReq; |
mr_q | 0:d8f2f7d5f31b | 271 | m_pDnsReq = NULL; |
mr_q | 0:d8f2f7d5f31b | 272 | } |
mr_q | 0:d8f2f7d5f31b | 273 | } |
mr_q | 0:d8f2f7d5f31b | 274 | |
mr_q | 0:d8f2f7d5f31b | 275 | void HTTPClient::setup(const char* uri, HTTPData* pDataOut, HTTPData* pDataIn) //Setup request, make DNS Req if necessary |
mr_q | 0:d8f2f7d5f31b | 276 | { |
mr_q | 0:d8f2f7d5f31b | 277 | DBG("HTTPClient::setup()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 278 | |
mr_q | 0:d8f2f7d5f31b | 279 | init(); //Initialize client in known state, create socket |
mr_q | 0:d8f2f7d5f31b | 280 | m_pDataOut = pDataOut; |
mr_q | 0:d8f2f7d5f31b | 281 | m_pDataIn = pDataIn; |
mr_q | 0:d8f2f7d5f31b | 282 | resetTimeout(); |
mr_q | 0:d8f2f7d5f31b | 283 | |
mr_q | 0:d8f2f7d5f31b | 284 | //Erase previous headers |
mr_q | 0:d8f2f7d5f31b | 285 | //Do NOT clear m_reqHeaders as they might have already set before connecting |
mr_q | 0:d8f2f7d5f31b | 286 | m_respHeaders.clear(); |
mr_q | 0:d8f2f7d5f31b | 287 | |
mr_q | 0:d8f2f7d5f31b | 288 | //Erase response buffer |
mr_q | 0:d8f2f7d5f31b | 289 | if(m_pDataIn) |
mr_q | 0:d8f2f7d5f31b | 290 | m_pDataIn->clear(); |
mr_q | 0:d8f2f7d5f31b | 291 | |
mr_q | 0:d8f2f7d5f31b | 292 | //Assert that buffers are initialized properly |
mr_q | 0:d8f2f7d5f31b | 293 | m_dataLen = 0; |
mr_q | 0:d8f2f7d5f31b | 294 | m_bufRemainingLen = 0; |
mr_q | 0:d8f2f7d5f31b | 295 | |
mr_q | 0:d8f2f7d5f31b | 296 | Url url; |
mr_q | 0:d8f2f7d5f31b | 297 | url.fromString(uri); |
mr_q | 0:d8f2f7d5f31b | 298 | |
mr_q | 0:d8f2f7d5f31b | 299 | m_path = url.getPath(); |
mr_q | 0:d8f2f7d5f31b | 300 | |
mr_q | 0:d8f2f7d5f31b | 301 | m_server.setName(url.getHost().c_str()); |
mr_q | 0:d8f2f7d5f31b | 302 | |
mr_q | 0:d8f2f7d5f31b | 303 | if( url.getPort() > 0 ) |
mr_q | 0:d8f2f7d5f31b | 304 | { |
mr_q | 0:d8f2f7d5f31b | 305 | m_server.setPort( url.getPort() ); |
mr_q | 0:d8f2f7d5f31b | 306 | } |
mr_q | 0:d8f2f7d5f31b | 307 | else |
mr_q | 0:d8f2f7d5f31b | 308 | { |
mr_q | 0:d8f2f7d5f31b | 309 | m_server.setPort( HTTP_PORT ); |
mr_q | 0:d8f2f7d5f31b | 310 | } |
mr_q | 0:d8f2f7d5f31b | 311 | |
mr_q | 0:d8f2f7d5f31b | 312 | DBG("URL parsed,\r\nHost: %s\r\nPort: %d\r\nPath: %s\r\n", url.getHost().c_str(), url.getPort(), url.getPath().c_str()); |
mr_q | 0:d8f2f7d5f31b | 313 | |
mr_q | 0:d8f2f7d5f31b | 314 | IpAddr ip; |
mr_q | 0:d8f2f7d5f31b | 315 | if( url.getHostIp(&ip) ) |
mr_q | 0:d8f2f7d5f31b | 316 | { |
mr_q | 0:d8f2f7d5f31b | 317 | m_server.setIp(ip); |
mr_q | 0:d8f2f7d5f31b | 318 | connect(); |
mr_q | 0:d8f2f7d5f31b | 319 | } |
mr_q | 0:d8f2f7d5f31b | 320 | else |
mr_q | 0:d8f2f7d5f31b | 321 | { |
mr_q | 0:d8f2f7d5f31b | 322 | DBG("DNS Query...\r\n"); |
mr_q | 0:d8f2f7d5f31b | 323 | m_pDnsReq = new DNSRequest(); |
mr_q | 0:d8f2f7d5f31b | 324 | m_pDnsReq->setOnReply(this, &HTTPClient::onDNSReply); |
mr_q | 0:d8f2f7d5f31b | 325 | m_pDnsReq->resolve(&m_server); |
mr_q | 0:d8f2f7d5f31b | 326 | DBG("HTTPClient : DNSRequest %p\r\n", m_pDnsReq); |
mr_q | 0:d8f2f7d5f31b | 327 | } |
mr_q | 0:d8f2f7d5f31b | 328 | |
mr_q | 0:d8f2f7d5f31b | 329 | } |
mr_q | 0:d8f2f7d5f31b | 330 | |
mr_q | 0:d8f2f7d5f31b | 331 | void HTTPClient::connect() //Start Connection |
mr_q | 0:d8f2f7d5f31b | 332 | { |
mr_q | 0:d8f2f7d5f31b | 333 | resetTimeout(); |
mr_q | 0:d8f2f7d5f31b | 334 | DBG("Connecting...\r\n"); |
mr_q | 0:d8f2f7d5f31b | 335 | m_pTCPSocket->connect(m_server); |
mr_q | 0:d8f2f7d5f31b | 336 | } |
mr_q | 0:d8f2f7d5f31b | 337 | |
mr_q | 0:d8f2f7d5f31b | 338 | #define MIN(a,b) ((a)<(b)?(a):(b)) |
mr_q | 0:d8f2f7d5f31b | 339 | #define ABS(a) (((a)>0)?(a):0) |
mr_q | 0:d8f2f7d5f31b | 340 | int HTTPClient::tryRead() //Try to read data from tcp packet and put in the HTTPData object |
mr_q | 0:d8f2f7d5f31b | 341 | { |
mr_q | 0:d8f2f7d5f31b | 342 | |
mr_q | 0:d8f2f7d5f31b | 343 | DBG("HTTPClient::tryRead()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 344 | |
mr_q | 0:d8f2f7d5f31b | 345 | int len = 0; |
mr_q | 0:d8f2f7d5f31b | 346 | int readLen; |
mr_q | 0:d8f2f7d5f31b | 347 | do |
mr_q | 0:d8f2f7d5f31b | 348 | { |
mr_q | 0:d8f2f7d5f31b | 349 | if(m_state == HTTP_READ_DATA_INCOMPLETE) //First try to complete buffer copy |
mr_q | 0:d8f2f7d5f31b | 350 | { |
mr_q | 0:d8f2f7d5f31b | 351 | readLen = m_bufRemainingLen; |
mr_q | 0:d8f2f7d5f31b | 352 | /* if (readLen == 0) |
mr_q | 0:d8f2f7d5f31b | 353 | { |
mr_q | 0:d8f2f7d5f31b | 354 | m_state = HTTP_READ_DATA; |
mr_q | 0:d8f2f7d5f31b | 355 | continue; |
mr_q | 0:d8f2f7d5f31b | 356 | }*/ |
mr_q | 0:d8f2f7d5f31b | 357 | } |
mr_q | 0:d8f2f7d5f31b | 358 | else |
mr_q | 0:d8f2f7d5f31b | 359 | { |
mr_q | 0:d8f2f7d5f31b | 360 | readLen = m_pTCPSocket->recv(m_buf, MIN(ABS(m_dataLen-m_dataPos),CHUNK_SIZE)); |
mr_q | 0:d8f2f7d5f31b | 361 | if(readLen < 0) //Error |
mr_q | 0:d8f2f7d5f31b | 362 | { |
mr_q | 0:d8f2f7d5f31b | 363 | return readLen; |
mr_q | 0:d8f2f7d5f31b | 364 | } |
mr_q | 0:d8f2f7d5f31b | 365 | |
mr_q | 0:d8f2f7d5f31b | 366 | DBG("%d bytes read\r\n", readLen); |
mr_q | 0:d8f2f7d5f31b | 367 | |
mr_q | 0:d8f2f7d5f31b | 368 | m_pBufRemaining = m_buf; |
mr_q | 0:d8f2f7d5f31b | 369 | } |
mr_q | 0:d8f2f7d5f31b | 370 | if (readLen == 0) |
mr_q | 0:d8f2f7d5f31b | 371 | { |
mr_q | 0:d8f2f7d5f31b | 372 | m_state = HTTP_READ_DATA; |
mr_q | 0:d8f2f7d5f31b | 373 | return len; |
mr_q | 0:d8f2f7d5f31b | 374 | } |
mr_q | 0:d8f2f7d5f31b | 375 | |
mr_q | 0:d8f2f7d5f31b | 376 | DBG("Trying to write %d bytes\r\n", readLen); |
mr_q | 0:d8f2f7d5f31b | 377 | |
mr_q | 0:d8f2f7d5f31b | 378 | int writtenLen = m_pDataIn->write(m_pBufRemaining, readLen); |
mr_q | 0:d8f2f7d5f31b | 379 | m_dataPos += writtenLen; |
mr_q | 0:d8f2f7d5f31b | 380 | |
mr_q | 0:d8f2f7d5f31b | 381 | DBG("%d bytes written\r\n", writtenLen); |
mr_q | 0:d8f2f7d5f31b | 382 | |
mr_q | 0:d8f2f7d5f31b | 383 | if(writtenLen<readLen) //Data was not completely written |
mr_q | 0:d8f2f7d5f31b | 384 | { |
mr_q | 0:d8f2f7d5f31b | 385 | m_pBufRemaining += writtenLen; |
mr_q | 0:d8f2f7d5f31b | 386 | m_bufRemainingLen = readLen - writtenLen; |
mr_q | 0:d8f2f7d5f31b | 387 | m_state = HTTP_READ_DATA_INCOMPLETE; |
mr_q | 0:d8f2f7d5f31b | 388 | return len + writtenLen; |
mr_q | 0:d8f2f7d5f31b | 389 | } |
mr_q | 0:d8f2f7d5f31b | 390 | else |
mr_q | 0:d8f2f7d5f31b | 391 | { |
mr_q | 0:d8f2f7d5f31b | 392 | m_state = HTTP_READ_DATA; |
mr_q | 0:d8f2f7d5f31b | 393 | } |
mr_q | 0:d8f2f7d5f31b | 394 | len += readLen; |
mr_q | 0:d8f2f7d5f31b | 395 | } while(readLen>0); |
mr_q | 0:d8f2f7d5f31b | 396 | |
mr_q | 0:d8f2f7d5f31b | 397 | return len; |
mr_q | 0:d8f2f7d5f31b | 398 | } |
mr_q | 0:d8f2f7d5f31b | 399 | |
mr_q | 0:d8f2f7d5f31b | 400 | void HTTPClient::readData() //Data has been read |
mr_q | 0:d8f2f7d5f31b | 401 | { |
mr_q | 0:d8f2f7d5f31b | 402 | DBG("HTTPClient::readData()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 403 | |
mr_q | 0:d8f2f7d5f31b | 404 | if(m_pDataIn == NULL) //Nothing to read (in HEAD for instance, not supported now) |
mr_q | 0:d8f2f7d5f31b | 405 | { |
mr_q | 0:d8f2f7d5f31b | 406 | m_state = HTTP_DONE; |
mr_q | 0:d8f2f7d5f31b | 407 | return; |
mr_q | 0:d8f2f7d5f31b | 408 | } |
mr_q | 0:d8f2f7d5f31b | 409 | DBG("Reading response...\r\n"); |
mr_q | 0:d8f2f7d5f31b | 410 | int len = 0; |
mr_q | 0:d8f2f7d5f31b | 411 | do |
mr_q | 0:d8f2f7d5f31b | 412 | { |
mr_q | 0:d8f2f7d5f31b | 413 | if(m_dataChunked && (m_state != HTTP_READ_DATA_INCOMPLETE)) |
mr_q | 0:d8f2f7d5f31b | 414 | { |
mr_q | 0:d8f2f7d5f31b | 415 | if(m_dataLen==0) |
mr_q | 0:d8f2f7d5f31b | 416 | { |
mr_q | 0:d8f2f7d5f31b | 417 | DBG("Reading chunk length...\r\n"); |
mr_q | 0:d8f2f7d5f31b | 418 | //New block |
mr_q | 0:d8f2f7d5f31b | 419 | static char chunkHeader[16]; |
mr_q | 0:d8f2f7d5f31b | 420 | //We use m_dataPos to retain the read position in chunkHeader, it has been set to 0 before the first call of readData() |
mr_q | 0:d8f2f7d5f31b | 421 | m_dataPos += readLine(chunkHeader + m_dataPos, ABS(16 - m_dataPos)); |
mr_q | 0:d8f2f7d5f31b | 422 | if( m_dataPos > 0 ) |
mr_q | 0:d8f2f7d5f31b | 423 | { |
mr_q | 0:d8f2f7d5f31b | 424 | if( chunkHeader[strlen(chunkHeader)-1] == 0x0d ) |
mr_q | 0:d8f2f7d5f31b | 425 | { |
mr_q | 0:d8f2f7d5f31b | 426 | sscanf(chunkHeader, "%x%*[^\r\n]", &m_dataLen); |
mr_q | 0:d8f2f7d5f31b | 427 | DBG("Chunk length is %d\n", m_dataLen); |
mr_q | 0:d8f2f7d5f31b | 428 | m_dataPos = 0; |
mr_q | 0:d8f2f7d5f31b | 429 | } |
mr_q | 0:d8f2f7d5f31b | 430 | else |
mr_q | 0:d8f2f7d5f31b | 431 | { |
mr_q | 0:d8f2f7d5f31b | 432 | //Wait for end of line |
mr_q | 0:d8f2f7d5f31b | 433 | DBG("Wait for CRLF\r\n"); |
mr_q | 0:d8f2f7d5f31b | 434 | return; |
mr_q | 0:d8f2f7d5f31b | 435 | } |
mr_q | 0:d8f2f7d5f31b | 436 | } |
mr_q | 0:d8f2f7d5f31b | 437 | else |
mr_q | 0:d8f2f7d5f31b | 438 | { |
mr_q | 0:d8f2f7d5f31b | 439 | DBG("Wait for data\r\n"); |
mr_q | 0:d8f2f7d5f31b | 440 | //Wait for data |
mr_q | 0:d8f2f7d5f31b | 441 | return; |
mr_q | 0:d8f2f7d5f31b | 442 | } |
mr_q | 0:d8f2f7d5f31b | 443 | } |
mr_q | 0:d8f2f7d5f31b | 444 | } |
mr_q | 0:d8f2f7d5f31b | 445 | |
mr_q | 0:d8f2f7d5f31b | 446 | //Proper data recovery |
mr_q | 0:d8f2f7d5f31b | 447 | len = tryRead(); |
mr_q | 0:d8f2f7d5f31b | 448 | if(len<0) //Error |
mr_q | 0:d8f2f7d5f31b | 449 | { |
mr_q | 0:d8f2f7d5f31b | 450 | onResult(HTTP_CONN); |
mr_q | 0:d8f2f7d5f31b | 451 | return; |
mr_q | 0:d8f2f7d5f31b | 452 | } |
mr_q | 0:d8f2f7d5f31b | 453 | |
mr_q | 0:d8f2f7d5f31b | 454 | if(len>0) |
mr_q | 0:d8f2f7d5f31b | 455 | resetTimeout(); |
mr_q | 0:d8f2f7d5f31b | 456 | |
mr_q | 0:d8f2f7d5f31b | 457 | if(m_state == HTTP_READ_DATA_INCOMPLETE) |
mr_q | 0:d8f2f7d5f31b | 458 | return; |
mr_q | 0:d8f2f7d5f31b | 459 | |
mr_q | 0:d8f2f7d5f31b | 460 | //Chunk Tail |
mr_q | 0:d8f2f7d5f31b | 461 | if(m_dataChunked) |
mr_q | 0:d8f2f7d5f31b | 462 | { |
mr_q | 0:d8f2f7d5f31b | 463 | if(m_dataPos >= m_dataLen) |
mr_q | 0:d8f2f7d5f31b | 464 | { |
mr_q | 0:d8f2f7d5f31b | 465 | DBG("Chunk read, wait for CRLF\n"); |
mr_q | 0:d8f2f7d5f31b | 466 | char chunkTail[3]; |
mr_q | 0:d8f2f7d5f31b | 467 | m_dataPos += readLine(chunkTail, 3); |
mr_q | 0:d8f2f7d5f31b | 468 | } |
mr_q | 0:d8f2f7d5f31b | 469 | |
mr_q | 0:d8f2f7d5f31b | 470 | if(m_dataPos >= m_dataLen + 1) //1 == strlen("\n"), |
mr_q | 0:d8f2f7d5f31b | 471 | { |
mr_q | 0:d8f2f7d5f31b | 472 | DBG("End of chunk\n"); |
mr_q | 0:d8f2f7d5f31b | 473 | if(m_dataLen==0) |
mr_q | 0:d8f2f7d5f31b | 474 | { |
mr_q | 0:d8f2f7d5f31b | 475 | DBG("End of file\n"); |
mr_q | 0:d8f2f7d5f31b | 476 | //End of file |
mr_q | 0:d8f2f7d5f31b | 477 | m_state = HTTP_DONE; //Done |
mr_q | 0:d8f2f7d5f31b | 478 | } |
mr_q | 0:d8f2f7d5f31b | 479 | m_dataLen = 0; |
mr_q | 0:d8f2f7d5f31b | 480 | m_dataPos = 0; |
mr_q | 0:d8f2f7d5f31b | 481 | } |
mr_q | 0:d8f2f7d5f31b | 482 | } |
mr_q | 0:d8f2f7d5f31b | 483 | |
mr_q | 0:d8f2f7d5f31b | 484 | } while(len>0); |
mr_q | 0:d8f2f7d5f31b | 485 | |
mr_q | 0:d8f2f7d5f31b | 486 | |
mr_q | 0:d8f2f7d5f31b | 487 | if(!m_dataChunked && (m_dataPos >= m_dataLen)) //All Data has been received |
mr_q | 0:d8f2f7d5f31b | 488 | { |
mr_q | 0:d8f2f7d5f31b | 489 | DBG("End of file\n"); |
mr_q | 0:d8f2f7d5f31b | 490 | m_state = HTTP_DONE; //Done |
mr_q | 0:d8f2f7d5f31b | 491 | } |
mr_q | 0:d8f2f7d5f31b | 492 | } |
mr_q | 0:d8f2f7d5f31b | 493 | |
mr_q | 0:d8f2f7d5f31b | 494 | void HTTPClient::writeData() //Data has been written & buf is free |
mr_q | 0:d8f2f7d5f31b | 495 | { |
mr_q | 0:d8f2f7d5f31b | 496 | DBG("HTTPClient::writeData()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 497 | |
mr_q | 0:d8f2f7d5f31b | 498 | if(m_pDataOut == NULL) //Nothing to write (in POST for instance) |
mr_q | 0:d8f2f7d5f31b | 499 | { |
mr_q | 0:d8f2f7d5f31b | 500 | m_dataLen = 0; //Reset Data Length |
mr_q | 0:d8f2f7d5f31b | 501 | m_state = HTTP_READ_HEADERS; |
mr_q | 0:d8f2f7d5f31b | 502 | return; |
mr_q | 0:d8f2f7d5f31b | 503 | } |
mr_q | 0:d8f2f7d5f31b | 504 | int len = m_pDataOut->read(m_buf, CHUNK_SIZE); |
mr_q | 0:d8f2f7d5f31b | 505 | if( m_dataChunked ) |
mr_q | 0:d8f2f7d5f31b | 506 | { |
mr_q | 0:d8f2f7d5f31b | 507 | //Write chunk header |
mr_q | 0:d8f2f7d5f31b | 508 | char chunkHeader[16]; |
mr_q | 0:d8f2f7d5f31b | 509 | sprintf(chunkHeader, "%d\r\n", len); |
mr_q | 0:d8f2f7d5f31b | 510 | int ret = m_pTCPSocket->send(chunkHeader, strlen(chunkHeader)); |
mr_q | 0:d8f2f7d5f31b | 511 | if(ret < 0)//Error |
mr_q | 0:d8f2f7d5f31b | 512 | { |
mr_q | 0:d8f2f7d5f31b | 513 | onResult(HTTP_CONN); |
mr_q | 0:d8f2f7d5f31b | 514 | return; |
mr_q | 0:d8f2f7d5f31b | 515 | } |
mr_q | 0:d8f2f7d5f31b | 516 | } |
mr_q | 0:d8f2f7d5f31b | 517 | m_pTCPSocket->send(m_buf, len); |
mr_q | 0:d8f2f7d5f31b | 518 | m_dataPos+=len; |
mr_q | 0:d8f2f7d5f31b | 519 | if( m_dataChunked ) |
mr_q | 0:d8f2f7d5f31b | 520 | { |
mr_q | 0:d8f2f7d5f31b | 521 | m_pTCPSocket->send("\r\n", 2); //Chunk-terminating CRLF |
mr_q | 0:d8f2f7d5f31b | 522 | } |
mr_q | 0:d8f2f7d5f31b | 523 | if( ( !m_dataChunked && (m_dataPos >= m_dataLen) ) |
mr_q | 0:d8f2f7d5f31b | 524 | || ( m_dataChunked && !len ) ) //All Data has been sent |
mr_q | 0:d8f2f7d5f31b | 525 | { |
mr_q | 0:d8f2f7d5f31b | 526 | m_dataLen = 0; //Reset Data Length |
mr_q | 0:d8f2f7d5f31b | 527 | m_state = HTTP_READ_HEADERS; //Wait for resp |
mr_q | 0:d8f2f7d5f31b | 528 | } |
mr_q | 0:d8f2f7d5f31b | 529 | } |
mr_q | 0:d8f2f7d5f31b | 530 | |
mr_q | 0:d8f2f7d5f31b | 531 | void HTTPClient::onTCPSocketEvent(TCPSocketEvent e) |
mr_q | 0:d8f2f7d5f31b | 532 | { |
mr_q | 0:d8f2f7d5f31b | 533 | DBG("Event %d in HTTPClient::onTCPSocketEvent()\r\n", e); |
mr_q | 0:d8f2f7d5f31b | 534 | |
mr_q | 0:d8f2f7d5f31b | 535 | if(m_closed) |
mr_q | 0:d8f2f7d5f31b | 536 | { |
mr_q | 0:d8f2f7d5f31b | 537 | DBG("WARN: Discarded\n"); |
mr_q | 0:d8f2f7d5f31b | 538 | return; |
mr_q | 0:d8f2f7d5f31b | 539 | } |
mr_q | 0:d8f2f7d5f31b | 540 | |
mr_q | 0:d8f2f7d5f31b | 541 | switch(e) |
mr_q | 0:d8f2f7d5f31b | 542 | { |
mr_q | 0:d8f2f7d5f31b | 543 | case TCPSOCKET_READABLE: //Incoming data |
mr_q | 0:d8f2f7d5f31b | 544 | resetTimeout(); |
mr_q | 0:d8f2f7d5f31b | 545 | switch(m_state) |
mr_q | 0:d8f2f7d5f31b | 546 | { |
mr_q | 0:d8f2f7d5f31b | 547 | case HTTP_READ_HEADERS: |
mr_q | 0:d8f2f7d5f31b | 548 | if( !readHeaders() ) |
mr_q | 0:d8f2f7d5f31b | 549 | { |
mr_q | 0:d8f2f7d5f31b | 550 | return; //Connection has been closed or incomplete data |
mr_q | 0:d8f2f7d5f31b | 551 | } |
mr_q | 0:d8f2f7d5f31b | 552 | if( m_pDataIn ) |
mr_q | 0:d8f2f7d5f31b | 553 | { |
mr_q | 0:d8f2f7d5f31b | 554 | //Data chunked? |
mr_q | 0:d8f2f7d5f31b | 555 | if(m_respHeaders["Transfer-Encoding"].find("chunked")!=string::npos) |
mr_q | 0:d8f2f7d5f31b | 556 | { |
mr_q | 0:d8f2f7d5f31b | 557 | m_dataChunked = true; |
mr_q | 0:d8f2f7d5f31b | 558 | m_dataPos = 0; |
mr_q | 0:d8f2f7d5f31b | 559 | m_dataLen = 0; |
mr_q | 0:d8f2f7d5f31b | 560 | DBG("Encoding is chunked, Content-Type is %s\n", m_respHeaders["Content-Type"].c_str() ); |
mr_q | 0:d8f2f7d5f31b | 561 | } |
mr_q | 0:d8f2f7d5f31b | 562 | else |
mr_q | 0:d8f2f7d5f31b | 563 | { |
mr_q | 0:d8f2f7d5f31b | 564 | m_dataChunked = false; |
mr_q | 0:d8f2f7d5f31b | 565 | int len = 0; |
mr_q | 0:d8f2f7d5f31b | 566 | //DBG("Preparing read... len = %s\n", m_respHeaders["Content-Length"].c_str()); |
mr_q | 0:d8f2f7d5f31b | 567 | sscanf(m_respHeaders["Content-Length"].c_str(), "%d", &len); |
mr_q | 0:d8f2f7d5f31b | 568 | m_pDataIn->setDataLen( len ); |
mr_q | 0:d8f2f7d5f31b | 569 | m_dataPos = 0; |
mr_q | 0:d8f2f7d5f31b | 570 | m_dataLen = len; |
mr_q | 0:d8f2f7d5f31b | 571 | DBG("Content-Length is %d, Content-Type is %s\n", len, m_respHeaders["Content-Type"].c_str() ); |
mr_q | 0:d8f2f7d5f31b | 572 | } |
mr_q | 0:d8f2f7d5f31b | 573 | m_pDataIn->setDataType( m_respHeaders["Content-Type"] ); |
mr_q | 0:d8f2f7d5f31b | 574 | } |
mr_q | 0:d8f2f7d5f31b | 575 | case HTTP_READ_DATA: |
mr_q | 0:d8f2f7d5f31b | 576 | readData(); |
mr_q | 0:d8f2f7d5f31b | 577 | break; |
mr_q | 0:d8f2f7d5f31b | 578 | case HTTP_READ_DATA_INCOMPLETE: |
mr_q | 0:d8f2f7d5f31b | 579 | break; //We need to handle previously received data first |
mr_q | 0:d8f2f7d5f31b | 580 | default: |
mr_q | 0:d8f2f7d5f31b | 581 | //Should not receive data now, req is not complete |
mr_q | 0:d8f2f7d5f31b | 582 | onResult(HTTP_PRTCL); |
mr_q | 0:d8f2f7d5f31b | 583 | } |
mr_q | 0:d8f2f7d5f31b | 584 | //All data has been read, close w/ success :) |
mr_q | 0:d8f2f7d5f31b | 585 | if( m_state == HTTP_DONE ) |
mr_q | 0:d8f2f7d5f31b | 586 | { |
mr_q | 0:d8f2f7d5f31b | 587 | DBG("Done :)!\n"); |
mr_q | 0:d8f2f7d5f31b | 588 | onResult(HTTP_OK); |
mr_q | 0:d8f2f7d5f31b | 589 | } |
mr_q | 0:d8f2f7d5f31b | 590 | break; |
mr_q | 0:d8f2f7d5f31b | 591 | case TCPSOCKET_CONNECTED: |
mr_q | 0:d8f2f7d5f31b | 592 | case TCPSOCKET_WRITEABLE: //We can send data |
mr_q | 0:d8f2f7d5f31b | 593 | resetTimeout(); |
mr_q | 0:d8f2f7d5f31b | 594 | switch(m_state) |
mr_q | 0:d8f2f7d5f31b | 595 | { |
mr_q | 0:d8f2f7d5f31b | 596 | case HTTP_WRITE_HEADERS: |
mr_q | 0:d8f2f7d5f31b | 597 | //Update headers fields according to m_pDataOut |
mr_q | 0:d8f2f7d5f31b | 598 | if( m_pDataOut ) |
mr_q | 0:d8f2f7d5f31b | 599 | { |
mr_q | 0:d8f2f7d5f31b | 600 | //Data is chunked? |
mr_q | 0:d8f2f7d5f31b | 601 | if(m_pDataOut->getIsChunked()) |
mr_q | 0:d8f2f7d5f31b | 602 | { |
mr_q | 0:d8f2f7d5f31b | 603 | m_dataChunked = true; |
mr_q | 0:d8f2f7d5f31b | 604 | m_reqHeaders.erase("Content-Length"); |
mr_q | 0:d8f2f7d5f31b | 605 | m_reqHeaders["Transfer-Encoding"] = "chunked"; |
mr_q | 0:d8f2f7d5f31b | 606 | } |
mr_q | 0:d8f2f7d5f31b | 607 | else |
mr_q | 0:d8f2f7d5f31b | 608 | { |
mr_q | 0:d8f2f7d5f31b | 609 | m_dataChunked = false; |
mr_q | 0:d8f2f7d5f31b | 610 | char c_len[16] = "0"; |
mr_q | 0:d8f2f7d5f31b | 611 | int len = m_pDataOut->getDataLen(); |
mr_q | 0:d8f2f7d5f31b | 612 | sprintf(c_len, "%d", len); |
mr_q | 0:d8f2f7d5f31b | 613 | m_dataPos = 0; |
mr_q | 0:d8f2f7d5f31b | 614 | m_dataLen = len; |
mr_q | 0:d8f2f7d5f31b | 615 | m_reqHeaders.erase("Transfer-Encoding"); |
mr_q | 0:d8f2f7d5f31b | 616 | m_reqHeaders["Content-Length"] = string(c_len); |
mr_q | 0:d8f2f7d5f31b | 617 | } |
mr_q | 0:d8f2f7d5f31b | 618 | string type = m_pDataOut->getDataType(); |
mr_q | 0:d8f2f7d5f31b | 619 | if(!type.empty()) |
mr_q | 0:d8f2f7d5f31b | 620 | { |
mr_q | 0:d8f2f7d5f31b | 621 | m_reqHeaders["Content-Type"] = type; |
mr_q | 0:d8f2f7d5f31b | 622 | } |
mr_q | 0:d8f2f7d5f31b | 623 | else |
mr_q | 0:d8f2f7d5f31b | 624 | { |
mr_q | 0:d8f2f7d5f31b | 625 | m_reqHeaders.erase("Content-Type"); |
mr_q | 0:d8f2f7d5f31b | 626 | } |
mr_q | 0:d8f2f7d5f31b | 627 | } |
mr_q | 0:d8f2f7d5f31b | 628 | if( !writeHeaders() ) |
mr_q | 0:d8f2f7d5f31b | 629 | { |
mr_q | 0:d8f2f7d5f31b | 630 | return; //Connection has been closed |
mr_q | 0:d8f2f7d5f31b | 631 | } |
mr_q | 0:d8f2f7d5f31b | 632 | break; //Wait for writeable event before sending payload |
mr_q | 0:d8f2f7d5f31b | 633 | case HTTP_WRITE_DATA: |
mr_q | 0:d8f2f7d5f31b | 634 | writeData(); |
mr_q | 0:d8f2f7d5f31b | 635 | break; |
mr_q | 0:d8f2f7d5f31b | 636 | } |
mr_q | 0:d8f2f7d5f31b | 637 | //Otherwise request has been sent, now wait for resp |
mr_q | 0:d8f2f7d5f31b | 638 | break; |
mr_q | 0:d8f2f7d5f31b | 639 | case TCPSOCKET_CONTIMEOUT: |
mr_q | 0:d8f2f7d5f31b | 640 | case TCPSOCKET_CONRST: |
mr_q | 0:d8f2f7d5f31b | 641 | case TCPSOCKET_CONABRT: |
mr_q | 0:d8f2f7d5f31b | 642 | case TCPSOCKET_ERROR: |
mr_q | 0:d8f2f7d5f31b | 643 | DBG("Connection error.\n"); |
mr_q | 0:d8f2f7d5f31b | 644 | onResult(HTTP_CONN); |
mr_q | 0:d8f2f7d5f31b | 645 | case TCPSOCKET_DISCONNECTED: |
mr_q | 0:d8f2f7d5f31b | 646 | //There might still be some data available for reading |
mr_q | 0:d8f2f7d5f31b | 647 | //So if we are in a reading state, do not close the socket yet |
mr_q | 0:d8f2f7d5f31b | 648 | if( (m_state != HTTP_READ_DATA_INCOMPLETE) && (m_state != HTTP_DONE) && (m_state != HTTP_CLOSED) ) |
mr_q | 0:d8f2f7d5f31b | 649 | { |
mr_q | 0:d8f2f7d5f31b | 650 | onResult(HTTP_CONN); |
mr_q | 0:d8f2f7d5f31b | 651 | } |
mr_q | 0:d8f2f7d5f31b | 652 | DBG("Connection closed by remote host.\n"); |
mr_q | 0:d8f2f7d5f31b | 653 | break; |
mr_q | 0:d8f2f7d5f31b | 654 | } |
mr_q | 0:d8f2f7d5f31b | 655 | } |
mr_q | 0:d8f2f7d5f31b | 656 | |
mr_q | 0:d8f2f7d5f31b | 657 | void HTTPClient::onDNSReply(DNSReply r) |
mr_q | 0:d8f2f7d5f31b | 658 | { |
mr_q | 0:d8f2f7d5f31b | 659 | if(m_closed) |
mr_q | 0:d8f2f7d5f31b | 660 | { |
mr_q | 0:d8f2f7d5f31b | 661 | DBG("WARN: Discarded\n"); |
mr_q | 0:d8f2f7d5f31b | 662 | return; |
mr_q | 0:d8f2f7d5f31b | 663 | } |
mr_q | 0:d8f2f7d5f31b | 664 | |
mr_q | 0:d8f2f7d5f31b | 665 | if( r != DNS_FOUND ) |
mr_q | 0:d8f2f7d5f31b | 666 | { |
mr_q | 0:d8f2f7d5f31b | 667 | DBG("Could not resolve hostname.\n"); |
mr_q | 0:d8f2f7d5f31b | 668 | onResult(HTTP_DNS); |
mr_q | 0:d8f2f7d5f31b | 669 | return; |
mr_q | 0:d8f2f7d5f31b | 670 | } |
mr_q | 0:d8f2f7d5f31b | 671 | |
mr_q | 0:d8f2f7d5f31b | 672 | DBG("DNS Resolved to %d.%d.%d.%d.\n",m_server.getIp()[0],m_server.getIp()[1],m_server.getIp()[2],m_server.getIp()[3]); |
mr_q | 0:d8f2f7d5f31b | 673 | //If no error, m_server has been updated by m_pDnsReq so we're set to go ! |
mr_q | 0:d8f2f7d5f31b | 674 | m_pDnsReq->close(); |
mr_q | 0:d8f2f7d5f31b | 675 | delete m_pDnsReq; |
mr_q | 0:d8f2f7d5f31b | 676 | m_pDnsReq = NULL; |
mr_q | 0:d8f2f7d5f31b | 677 | connect(); |
mr_q | 0:d8f2f7d5f31b | 678 | } |
mr_q | 0:d8f2f7d5f31b | 679 | |
mr_q | 0:d8f2f7d5f31b | 680 | void HTTPClient::onResult(HTTPResult r) //Called when exchange completed or on failure |
mr_q | 0:d8f2f7d5f31b | 681 | { |
mr_q | 0:d8f2f7d5f31b | 682 | DBG("HTTPClient::onResult()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 683 | |
mr_q | 0:d8f2f7d5f31b | 684 | if(m_pCbItem && m_pCbMeth) |
mr_q | 0:d8f2f7d5f31b | 685 | (m_pCbItem->*m_pCbMeth)(r); |
mr_q | 0:d8f2f7d5f31b | 686 | else if(m_pCb) |
mr_q | 0:d8f2f7d5f31b | 687 | m_pCb(r); |
mr_q | 0:d8f2f7d5f31b | 688 | m_blockingResult = r; //Blocking mode |
mr_q | 0:d8f2f7d5f31b | 689 | close(); //FIXME:Remove suppl. close() calls |
mr_q | 0:d8f2f7d5f31b | 690 | } |
mr_q | 0:d8f2f7d5f31b | 691 | |
mr_q | 0:d8f2f7d5f31b | 692 | void HTTPClient::onTimeout() //Connection has timed out |
mr_q | 0:d8f2f7d5f31b | 693 | { |
mr_q | 0:d8f2f7d5f31b | 694 | DBG("Timed out.\r\n"); |
mr_q | 0:d8f2f7d5f31b | 695 | onResult(HTTP_TIMEOUT); |
mr_q | 0:d8f2f7d5f31b | 696 | close(); |
mr_q | 0:d8f2f7d5f31b | 697 | } |
mr_q | 0:d8f2f7d5f31b | 698 | |
mr_q | 0:d8f2f7d5f31b | 699 | //Headers |
mr_q | 0:d8f2f7d5f31b | 700 | |
mr_q | 0:d8f2f7d5f31b | 701 | //TODO: Factorize w/ HTTPRequestHandler in a single HTTPHeader class |
mr_q | 0:d8f2f7d5f31b | 702 | |
mr_q | 0:d8f2f7d5f31b | 703 | HTTPResult HTTPClient::blockingProcess() //Called in blocking mode, calls Net::poll() until return code is available |
mr_q | 0:d8f2f7d5f31b | 704 | { |
mr_q | 0:d8f2f7d5f31b | 705 | //Disable callbacks |
mr_q | 0:d8f2f7d5f31b | 706 | m_pCb = NULL; |
mr_q | 0:d8f2f7d5f31b | 707 | m_pCbItem = NULL; |
mr_q | 0:d8f2f7d5f31b | 708 | m_pCbMeth = NULL; |
mr_q | 0:d8f2f7d5f31b | 709 | m_blockingResult = HTTP_PROCESSING; |
mr_q | 0:d8f2f7d5f31b | 710 | do |
mr_q | 0:d8f2f7d5f31b | 711 | { |
mr_q | 0:d8f2f7d5f31b | 712 | Net::poll(); |
mr_q | 0:d8f2f7d5f31b | 713 | } while(m_blockingResult == HTTP_PROCESSING); |
mr_q | 0:d8f2f7d5f31b | 714 | Net::poll(); //Necessary for cleanup |
mr_q | 0:d8f2f7d5f31b | 715 | return m_blockingResult; |
mr_q | 0:d8f2f7d5f31b | 716 | } |
mr_q | 0:d8f2f7d5f31b | 717 | |
mr_q | 0:d8f2f7d5f31b | 718 | bool HTTPClient::readHeaders() |
mr_q | 0:d8f2f7d5f31b | 719 | { |
mr_q | 0:d8f2f7d5f31b | 720 | DBG("HTTPClient::readHeaders()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 721 | |
mr_q | 0:d8f2f7d5f31b | 722 | static char* line = m_buf; |
mr_q | 0:d8f2f7d5f31b | 723 | static char key[128]; |
mr_q | 0:d8f2f7d5f31b | 724 | static char value[128]; |
mr_q | 0:d8f2f7d5f31b | 725 | if(!m_dataLen) //No incomplete header in buffer, this is the first time we read data |
mr_q | 0:d8f2f7d5f31b | 726 | { |
mr_q | 0:d8f2f7d5f31b | 727 | if( readLine(line, 128) > 0 ) |
mr_q | 0:d8f2f7d5f31b | 728 | { |
mr_q | 0:d8f2f7d5f31b | 729 | //Check RC |
mr_q | 0:d8f2f7d5f31b | 730 | m_httpResponseCode = 0; |
mr_q | 0:d8f2f7d5f31b | 731 | if( sscanf(line, "HTTP/%*d.%*d %d %*[^\r\n]", &m_httpResponseCode) != 1 ) |
mr_q | 0:d8f2f7d5f31b | 732 | { |
mr_q | 0:d8f2f7d5f31b | 733 | //Cannot match string, error |
mr_q | 0:d8f2f7d5f31b | 734 | DBG("Not a correct HTTP answer : %s\n", line); |
mr_q | 0:d8f2f7d5f31b | 735 | onResult(HTTP_PRTCL); |
mr_q | 0:d8f2f7d5f31b | 736 | close(); |
mr_q | 0:d8f2f7d5f31b | 737 | return false; |
mr_q | 0:d8f2f7d5f31b | 738 | } |
mr_q | 0:d8f2f7d5f31b | 739 | |
mr_q | 0:d8f2f7d5f31b | 740 | if(m_httpResponseCode != 200) |
mr_q | 0:d8f2f7d5f31b | 741 | { |
mr_q | 0:d8f2f7d5f31b | 742 | DBG("Response: error code %d\n", m_httpResponseCode); |
mr_q | 0:d8f2f7d5f31b | 743 | HTTPResult res = HTTP_ERROR; |
mr_q | 0:d8f2f7d5f31b | 744 | switch(m_httpResponseCode) |
mr_q | 0:d8f2f7d5f31b | 745 | { |
mr_q | 0:d8f2f7d5f31b | 746 | case 404: |
mr_q | 0:d8f2f7d5f31b | 747 | res = HTTP_NOTFOUND; |
mr_q | 0:d8f2f7d5f31b | 748 | break; |
mr_q | 0:d8f2f7d5f31b | 749 | case 403: |
mr_q | 0:d8f2f7d5f31b | 750 | res = HTTP_REFUSED; |
mr_q | 0:d8f2f7d5f31b | 751 | break; |
mr_q | 0:d8f2f7d5f31b | 752 | default: |
mr_q | 0:d8f2f7d5f31b | 753 | res = HTTP_ERROR; |
mr_q | 0:d8f2f7d5f31b | 754 | } |
mr_q | 0:d8f2f7d5f31b | 755 | onResult(res); |
mr_q | 0:d8f2f7d5f31b | 756 | close(); |
mr_q | 0:d8f2f7d5f31b | 757 | return false; |
mr_q | 0:d8f2f7d5f31b | 758 | } |
mr_q | 0:d8f2f7d5f31b | 759 | DBG("Response OK\n"); |
mr_q | 0:d8f2f7d5f31b | 760 | } |
mr_q | 0:d8f2f7d5f31b | 761 | else |
mr_q | 0:d8f2f7d5f31b | 762 | { |
mr_q | 0:d8f2f7d5f31b | 763 | //Empty packet, weird! |
mr_q | 0:d8f2f7d5f31b | 764 | DBG("Empty packet!\n"); |
mr_q | 0:d8f2f7d5f31b | 765 | onResult(HTTP_PRTCL); |
mr_q | 0:d8f2f7d5f31b | 766 | close(); |
mr_q | 0:d8f2f7d5f31b | 767 | return false; |
mr_q | 0:d8f2f7d5f31b | 768 | } |
mr_q | 0:d8f2f7d5f31b | 769 | } |
mr_q | 0:d8f2f7d5f31b | 770 | bool incomplete = false; |
mr_q | 0:d8f2f7d5f31b | 771 | while( true ) |
mr_q | 0:d8f2f7d5f31b | 772 | { |
mr_q | 0:d8f2f7d5f31b | 773 | int readLen = readLine(line + m_dataLen, 128 - m_dataLen, &incomplete); |
mr_q | 0:d8f2f7d5f31b | 774 | m_dataLen = 0; |
mr_q | 0:d8f2f7d5f31b | 775 | if( readLen <= 2 ) //if == 1 or 2, it is an empty line = end of headers |
mr_q | 0:d8f2f7d5f31b | 776 | { |
mr_q | 0:d8f2f7d5f31b | 777 | DBG("All headers read.\n"); |
mr_q | 0:d8f2f7d5f31b | 778 | m_state = HTTP_READ_DATA; |
mr_q | 0:d8f2f7d5f31b | 779 | break; |
mr_q | 0:d8f2f7d5f31b | 780 | } |
mr_q | 0:d8f2f7d5f31b | 781 | else if( incomplete == true ) |
mr_q | 0:d8f2f7d5f31b | 782 | { |
mr_q | 0:d8f2f7d5f31b | 783 | m_dataLen = readLen;//Sets data length available in buffer |
mr_q | 0:d8f2f7d5f31b | 784 | return false; |
mr_q | 0:d8f2f7d5f31b | 785 | } |
mr_q | 0:d8f2f7d5f31b | 786 | //DBG("Header : %s\n", line); |
mr_q | 0:d8f2f7d5f31b | 787 | int n = sscanf(line, "%[^:] : %[^\r\n]", key, value); |
mr_q | 0:d8f2f7d5f31b | 788 | if ( n == 2 ) |
mr_q | 0:d8f2f7d5f31b | 789 | { |
mr_q | 0:d8f2f7d5f31b | 790 | DBG("Read header : %s: %s\n", key, value); |
mr_q | 0:d8f2f7d5f31b | 791 | m_respHeaders[key] = value; |
mr_q | 0:d8f2f7d5f31b | 792 | } |
mr_q | 0:d8f2f7d5f31b | 793 | //TODO: Impl n==1 case (part 2 of previous header) |
mr_q | 0:d8f2f7d5f31b | 794 | } |
mr_q | 0:d8f2f7d5f31b | 795 | |
mr_q | 0:d8f2f7d5f31b | 796 | return true; |
mr_q | 0:d8f2f7d5f31b | 797 | } |
mr_q | 0:d8f2f7d5f31b | 798 | |
mr_q | 0:d8f2f7d5f31b | 799 | bool HTTPClient::writeHeaders() //Called at the first writeData call |
mr_q | 0:d8f2f7d5f31b | 800 | { |
mr_q | 0:d8f2f7d5f31b | 801 | static char* line = m_buf; |
mr_q | 0:d8f2f7d5f31b | 802 | const char* HTTP_METH_STR[] = {"GET", "POST", "HEAD"}; |
mr_q | 0:d8f2f7d5f31b | 803 | |
mr_q | 0:d8f2f7d5f31b | 804 | //Req |
mr_q | 0:d8f2f7d5f31b | 805 | sprintf(line, "%s %s HTTP/1.1\r\nHost: %s\r\n", HTTP_METH_STR[m_meth], m_path.c_str(), m_server.getName()); //Write request |
mr_q | 0:d8f2f7d5f31b | 806 | m_pTCPSocket->send(line, strlen(line)); |
mr_q | 0:d8f2f7d5f31b | 807 | DBG("Request: %s\n", line); |
mr_q | 0:d8f2f7d5f31b | 808 | |
mr_q | 0:d8f2f7d5f31b | 809 | DBG("Writing headers:\n"); |
mr_q | 0:d8f2f7d5f31b | 810 | map<string,string>::iterator it; |
mr_q | 0:d8f2f7d5f31b | 811 | for( it = m_reqHeaders.begin(); it != m_reqHeaders.end(); it++ ) |
mr_q | 0:d8f2f7d5f31b | 812 | { |
mr_q | 0:d8f2f7d5f31b | 813 | sprintf(line, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() ); |
mr_q | 0:d8f2f7d5f31b | 814 | DBG("\r\n%s", line); |
mr_q | 0:d8f2f7d5f31b | 815 | m_pTCPSocket->send(line, strlen(line)); |
mr_q | 0:d8f2f7d5f31b | 816 | } |
mr_q | 0:d8f2f7d5f31b | 817 | m_pTCPSocket->send("\r\n",2); //End of head |
mr_q | 0:d8f2f7d5f31b | 818 | m_state = HTTP_WRITE_DATA; |
mr_q | 0:d8f2f7d5f31b | 819 | return true; |
mr_q | 0:d8f2f7d5f31b | 820 | } |
mr_q | 0:d8f2f7d5f31b | 821 | |
mr_q | 0:d8f2f7d5f31b | 822 | int HTTPClient::readLine(char* str, int maxLen, bool* pIncomplete /* = NULL*/) |
mr_q | 0:d8f2f7d5f31b | 823 | { |
mr_q | 0:d8f2f7d5f31b | 824 | DBG("HTTPClient::readLine()\r\n"); |
mr_q | 0:d8f2f7d5f31b | 825 | |
mr_q | 0:d8f2f7d5f31b | 826 | int ret; |
mr_q | 0:d8f2f7d5f31b | 827 | int len = 0; |
mr_q | 0:d8f2f7d5f31b | 828 | if(pIncomplete) |
mr_q | 0:d8f2f7d5f31b | 829 | *pIncomplete = false; |
mr_q | 0:d8f2f7d5f31b | 830 | for(int i = 0; i < maxLen - 1; i++) |
mr_q | 0:d8f2f7d5f31b | 831 | { |
mr_q | 0:d8f2f7d5f31b | 832 | ret = m_pTCPSocket->recv(str, 1); |
mr_q | 0:d8f2f7d5f31b | 833 | if(ret != 1) |
mr_q | 0:d8f2f7d5f31b | 834 | { |
mr_q | 0:d8f2f7d5f31b | 835 | if(pIncomplete) |
mr_q | 0:d8f2f7d5f31b | 836 | *pIncomplete = true; |
mr_q | 0:d8f2f7d5f31b | 837 | break; |
mr_q | 0:d8f2f7d5f31b | 838 | } |
mr_q | 0:d8f2f7d5f31b | 839 | if( (len > 1) && *(str-1)=='\r' && *str=='\n' ) |
mr_q | 0:d8f2f7d5f31b | 840 | { |
mr_q | 0:d8f2f7d5f31b | 841 | break; |
mr_q | 0:d8f2f7d5f31b | 842 | } |
mr_q | 0:d8f2f7d5f31b | 843 | else if( *str=='\n' ) |
mr_q | 0:d8f2f7d5f31b | 844 | { |
mr_q | 0:d8f2f7d5f31b | 845 | break; |
mr_q | 0:d8f2f7d5f31b | 846 | } |
mr_q | 0:d8f2f7d5f31b | 847 | str++; |
mr_q | 0:d8f2f7d5f31b | 848 | len++; |
mr_q | 0:d8f2f7d5f31b | 849 | } |
mr_q | 0:d8f2f7d5f31b | 850 | *str = 0; |
mr_q | 0:d8f2f7d5f31b | 851 | return len; |
mr_q | 0:d8f2f7d5f31b | 852 | } |