22 #include "wsresponse.h" 23 #include "securesocket.h" 26 #include "compressor.h" 32 #define HTTP_TOKEN_MAXSIZE 20 33 #define HTTP_HEADER_MAXSIZE 4000 34 #define RESPONSE_BUFFER_SIZE 4000 38 bool WSResponse::ReadHeaderLine(
NetSocket *socket,
const char *eol, std::string& line,
size_t *len)
40 char buf[RESPONSE_BUFFER_SIZE];
42 int p = 0, p_eol = 0, l_eol;
49 l_eol = strlen(s_eol);
54 if (socket->ReceiveData(&buf[p], 1) > 0)
56 if (buf[p++] == s_eol[p_eol])
60 buf[p - l_eol] =
'\0';
69 if (p > (RESPONSE_BUFFER_SIZE - 2 - l_eol))
85 while (l < HTTP_HEADER_MAXSIZE);
91 WSResponse::WSResponse(
const WSRequest &request)
98 , m_contentType(CT_NONE)
99 , m_contentEncoding(CE_NONE)
100 , m_contentChunked(false)
109 if (request.IsSecureURI())
110 m_socket = SSLSessionFactory::Instance().NewSocket();
114 DBG(DBG_ERROR,
"%s: create socket failed\n", __FUNCTION__);
115 else if (m_socket->Connect(request.GetServer().c_str(), request.GetPort(), SOCKET_RCVBUF_MINSIZE))
117 m_socket->SetReadAttempt(6);
118 if (SendRequest(request) && GetResponse())
120 if (m_statusCode < 200)
121 DBG(DBG_WARN,
"%s: status %d\n", __FUNCTION__, m_statusCode);
122 else if (m_statusCode < 300)
124 else if (m_statusCode < 400)
125 m_successful =
false;
126 else if (m_statusCode < 500)
127 DBG(DBG_ERROR,
"%s: bad request (%d)\n", __FUNCTION__, m_statusCode);
129 DBG(DBG_ERROR,
"%s: server error (%d)\n", __FUNCTION__, m_statusCode);
132 DBG(DBG_ERROR,
"%s: invalid response\n", __FUNCTION__);
136 WSResponse::~WSResponse()
138 SAFE_DELETE(m_decoder);
139 SAFE_DELETE_ARRAY(m_chunkBuffer);
140 SAFE_DELETE(m_socket);
143 bool WSResponse::SendRequest(
const WSRequest &request)
147 request.MakeMessage(msg);
148 DBG(DBG_PROTO,
"%s: %s\n", __FUNCTION__, msg.c_str());
149 if (!m_socket->SendData(msg.c_str(), msg.size()))
151 DBG(DBG_ERROR,
"%s: failed (%d)\n", __FUNCTION__, m_socket->GetErrNo());
157 bool WSResponse::GetResponse()
161 char token[HTTP_TOKEN_MAXSIZE + 1];
162 int n = 0, token_len = 0;
166 while (ReadHeaderLine(m_socket,
"\r\n", strread, &len))
168 const char *line = strread.c_str(), *val = NULL;
171 DBG(DBG_PROTO,
"%s: %s\n", __FUNCTION__, line);
180 if (len > 5 && 0 == memcmp(line,
"HTTP", 4) && 1 == sscanf(line,
"%*s %d", &status))
183 m_statusCode = status;
203 if ((line[0] ==
' ' || line[0] ==
'\t') && token_len)
213 else if ((val = strchr(line,
':')))
216 if ((token_len = val - line) > HTTP_TOKEN_MAXSIZE)
217 token_len = HTTP_TOKEN_MAXSIZE;
218 for (p = 0; p < token_len; ++p)
219 token[p] = toupper(line[p]);
220 token[token_len] = 0;
221 value_len = len - (val - line + 1);
222 while (*(++val) ==
' ' && value_len > 0) --value_len;
223 m_headers.push_front(std::make_pair(token,
""));
229 token[token_len] = 0;
234 m_headers.front().second.append(val);
238 if (memcmp(token,
"ETAG", token_len) == 0)
242 if (memcmp(token,
"SERVER", token_len) == 0)
243 m_serverInfo.append(val);
246 if (memcmp(token,
"LOCATION", token_len) == 0)
247 m_location.append(val);
250 if (memcmp(token,
"CONTENT-TYPE", token_len) == 0)
251 m_contentType = ContentTypeFromMime(val);
254 if (memcmp(token,
"CONTENT-LENGTH", token_len) == 0)
255 m_contentLength = atol(val);
258 if (memcmp(token,
"CONTENT-ENCODING", token_len) == 0)
260 if (value_len > 6 && memcmp(val,
"deflate", 7) == 0)
261 m_contentEncoding = CE_DEFLATE;
262 else if (value_len > 3 && memcmp(val,
"gzip", 4) == 0)
263 m_contentEncoding = CE_GZIP;
266 m_contentEncoding = CE_UNKNOWN;
267 DBG(DBG_ERROR,
"%s: unsupported content encoding (%s) %d\n", __FUNCTION__, val, value_len);
272 if (memcmp(token,
"TRANSFER-ENCODING", token_len) == 0)
274 if (value_len > 6 && memcmp(val,
"chunked", 7) == 0)
275 m_contentChunked =
true;
287 size_t WSResponse::ReadChunk(
void *buf,
size_t buflen)
290 if (m_contentChunked)
293 if (m_chunkPtr >= m_chunkEnd)
296 SAFE_DELETE_ARRAY(m_chunkBuffer);
297 m_chunkBuffer = m_chunkPtr = m_chunkEOR = m_chunkEnd = NULL;
300 while (ReadHeaderLine(m_socket,
"\r\n", strread, &len) && len == 0);
301 DBG(DBG_PROTO,
"%s: chunked data (%s)\n", __FUNCTION__, strread.c_str());
302 std::string chunkStr(
"0x0");
304 if (!strread.empty() && sscanf(chunkStr.append(strread).c_str(),
"%x", &chunkSize) == 1 && chunkSize > 0)
306 if (!(m_chunkBuffer =
new char[chunkSize]))
308 m_chunkPtr = m_chunkEOR = m_chunkBuffer;
309 m_chunkEnd = m_chunkBuffer + chunkSize;
315 if (m_chunkPtr >= m_chunkEOR)
319 m_chunkEOR += m_socket->ReceiveData(m_chunkEOR, m_chunkEnd - m_chunkEOR);
321 if ((s = m_chunkEOR - m_chunkPtr) > buflen)
323 memcpy(buf, m_chunkPtr, s);
330 int WSResponse::SocketStreamReader(
void *hdl,
void *buf,
int sz)
337 if (!resp->m_contentLength)
339 else if (resp->m_contentLength > resp->m_consumed)
341 size_t len = resp->m_contentLength - resp->m_consumed;
342 s = resp->m_socket->
ReceiveData(buf, len > (
size_t)sz ? (
size_t)sz : len);
344 resp->m_consumed += s;
348 int WSResponse::ChunkStreamReader(
void *hdl,
void *buf,
int sz)
351 return (resp == NULL ? 0 : resp->ReadChunk(buf, sz));
354 size_t WSResponse::ReadContent(
char* buf,
size_t buflen)
357 if (!m_contentChunked)
359 if (m_contentEncoding == CE_NONE)
362 if (!m_contentLength)
363 s = m_socket->ReceiveData(buf, buflen);
364 else if (m_contentLength > m_consumed)
366 size_t len = m_contentLength - m_consumed;
367 s = m_socket->ReceiveData(buf, len > buflen ? buflen : len);
371 else if (m_contentEncoding == CE_GZIP || m_contentEncoding == CE_DEFLATE)
373 if (m_decoder == NULL)
374 m_decoder =
new Decompressor(&SocketStreamReader,
this);
375 if (m_decoder->HasOutputData())
376 s = m_decoder->ReadOutput(buf, buflen);
377 if (s == 0 && !m_decoder->IsCompleted())
379 if (m_decoder->HasStreamError())
380 DBG(DBG_ERROR,
"%s: decoding failed: stream error\n", __FUNCTION__);
381 else if (m_decoder->HasBufferError())
382 DBG(DBG_ERROR,
"%s: decoding failed: buffer error\n", __FUNCTION__);
384 DBG(DBG_ERROR,
"%s: decoding failed\n", __FUNCTION__);
390 if (m_contentEncoding == CE_NONE)
392 s = ReadChunk(buf, buflen);
394 else if (m_contentEncoding == CE_GZIP || m_contentEncoding == CE_DEFLATE)
396 if (m_decoder == NULL)
398 if (m_decoder->HasOutputData())
399 s = m_decoder->ReadOutput(buf, buflen);
400 if (s == 0 && !m_decoder->IsCompleted())
402 if (m_decoder->HasStreamError())
403 DBG(DBG_ERROR,
"%s: decoding failed: stream error\n", __FUNCTION__);
404 else if (m_decoder->HasBufferError())
405 DBG(DBG_ERROR,
"%s: decoding failed: buffer error\n", __FUNCTION__);
407 DBG(DBG_ERROR,
"%s: decoding failed\n", __FUNCTION__);
414 bool WSResponse::GetHeaderValue(
const std::string& header, std::string& value)
416 for (HeaderList::const_iterator it = m_headers.begin(); it != m_headers.end(); ++it)
418 if (it->first != header)
420 value.assign(it->second);
char * m_chunkPtr
The next position to read data from the chunk.
char * m_chunkBuffer
The chunk data buffer.
char * m_chunkEOR
The end of received data in the chunk.
char * m_chunkEnd
The end of the chunk buffer.
virtual size_t ReceiveData(void *buf, size_t n)