Permalink
Browse files

fixed the method of reading chunked content.

  • Loading branch information...
1 parent c63a84a commit 8da41e0eadfd99589f6c3def03f4854940cbb1bb Terushi Arakawa committed Nov 21, 2012
Showing with 127 additions and 356 deletions.
  1. +1 −7 Src/Connection/WebClient/WebClient.hpp
  2. +126 −349 Src/Connection/WebClient/WebClientHandler.cpp
View
8 Src/Connection/WebClient/WebClient.hpp
@@ -137,14 +137,8 @@ class GOOGLEPLUSLIBRARY_API WebClient
void handleReadContent(const boost_error_code& error, size_t bytes_transferred);
void startReadChunkedContent();
-
void handleReadChunkSize(const boost_error_code& error, size_t bytes_transferred);
- void handleReadChunkSize2(const boost_error_code& error, size_t bytes_transferred);
- void handleReadEndSize(const boost_error_code& error, size_t bytes_transferred);
- void handleReadEndLine(const boost_error_code& error, size_t bytes_transferred);
- void handleReadChunkedContent(const boost_error_code& error, size_t bytes_transferred);
- void handleReadChunkedContent2(const boost_error_code& error, size_t bytes_transferred);
- void handleReadChunkedContent3(const boost_error_code& error, size_t bytes_transferred);
+ void handleReadChunkData(const boost_error_code& error, size_t bytes_transferred);
private:
std::shared_ptr<boost::asio::io_service> io_service_ptr_;
boost::asio::io_service& io_service_;
View
475 Src/Connection/WebClient/WebClientHandler.cpp
@@ -7,6 +7,7 @@
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/regex.hpp>
+#include <boost/lexical_cast.hpp>
#include <iostream>
#include <fstream>
@@ -297,389 +298,165 @@ void WebClient::startReadChunkedContent()
//cout << "LoadHandleReadChunkSize" << endl;
connect_timer_.expires_from_now(boost::posix_time::seconds(30));
- /*
- boost::asio::async_read_until(socket_, response_, "\n",
- boost::bind(&WebClient::handleReadChunkSize, this,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred));
- */
- boost::asio::async_read_until(socket_, response_, "\n",
- boost::bind(&WebClient::handleReadChunkedContent, this,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred));
+ boost::asio::async_read_until(socket_, response_, "\r\n",
+ boost::bind(&WebClient::handleReadChunkSize, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred));
}
-void WebClient::handleReadChunkSize(const boost_error_code& error, size_t bytes_transferred)
+#define NO_DEBUG_WITH_HEXDUMP
+#if defined DEBUG_WITH_HEXDUMP
+static void hexdump(const char *buf, size_t len)
{
- cout << "HandleReadChunkSize" << endl;
-
- if (is_cancellation_pending_)
- {
- cancelConnect();
- return;
- }
-
- if (error)
- {
- cout << "Error on receive: " << error.message() << endl;
- cancelConnect();
- return;
- }
-
- string line = string(boost::asio::buffer_cast<const char*>(response_.data()), bytes_transferred);
- response_.consume(bytes_transferred);
-
- size_t size = -1;
-
- if(qi::parse(line.cbegin(), line.cend(), qi::hex[phoenix::ref(size) = qi::_1] >> (qi::lit("\r\n") | qi::lit("\n"))))
- {
- if(size == 0)
- {
- cancelConnect();
- }
- else
- {
- cout << "LoadHandleReadChunkedContent" << endl;
- cout << "Chunk Size:" <<size << endl;
-
- boost::asio::async_read(socket_, response_,
- boost::asio::transfer_exactly(size),
- boost::bind(&WebClient::handleReadChunkedContent3, this,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred));
- }
- }
- else
- {
- cancelConnect();
- }
+ // xxxxxxx aa aa aa aa aa aa aa aa:aa aa aa aa aa aa aa aa aaaaaaaaaaaaaaaa
+ char line[] = " : ";
+ static const char hc[] = "0123456789abcdef";
+ for (size_t i = 0; i < len; ++i) {
+ int c = (unsigned char)buf[i];
+ size_t offset = i % 16;
+ if (offset == 0) {
+ if (i != 0)
+ puts(line);
+ sprintf(line, "%07x", (unsigned int)i);
+ memset(line + 7, ' ', sizeof line - 8);
+ line[31] = ':';
+ line[55] = '|';
+ }
+ char *p = line + 8 + offset * 3;
+ p[0] = hc[(c >> 4) & 0xfU];
+ p[1] = hc[c & 0xfU];
+ line[56 + offset] = isprint(c) ? c : ' ';
+ }
+ puts(line);
}
+#endif //DEBUG_WITH_HEXDUMP
-void WebClient::handleReadChunkSize2(const boost_error_code& error, size_t bytes_transferred)
+static size_t hex2size_t(const std::string str)
{
- //cout << "HandleReadChunkSize" << endl;
-
- if (is_cancellation_pending_)
- {
- return;
- }
-
- if (error)
- {
- cout << "Error on receive: " << error.message() << endl;
- cancelConnect();
- return;
- }
-
- string line = string(boost::asio::buffer_cast<const char*>(response_.data()), bytes_transferred);
- response_.consume(bytes_transferred);
- if(line.find("0\r\n") >= 0)
- {
- int a = 3;
- }
- int size = -1;
-
- if(qi::parse(line.cbegin(), line.cend(), qi::hex[phoenix::ref(size) = qi::_1] >> (qi::lit("\r\n") | qi::lit("\n"))))
- {
- if(size == 0)
- {
- cout << "handleReadChunkSize2 size == 0----------------------------------------------------------------" << endl;
- cancelConnect();
- return;
- }
- read_size_ = size;
- //read_mode_ = ReadEndSize;
- read_mode_ = ReadChunkedContent;
- startReadChunkedContent();
- }
- else
- {
- cout << "handleReadChunkSize2 parse failed----------------------------------------------------------------" << endl;
- cancelConnect();
- return;
- }
-
+ size_t size = 0;
+ for (const char *p = str.c_str(); *p; ++p) {
+ switch (*p) {
+ // case '0': break; // nothing to do
+ case '1':
+ size += 1;
+ break;
+ case '2':
+ size += 2;
+ break;
+ case '3':
+ size += 3;
+ break;
+ case '4':
+ size += 4;
+ break;
+ case '5':
+ size += 5;
+ break;
+ case '6':
+ size += 6;
+ break;
+ case '7':
+ size += 7;
+ break;
+ case '8':
+ size += 8;
+ break;
+ case '9':
+ size += 9;
+ break;
+ case 'A':
+ case 'a':
+ size += 10;
+ break;
+ case 'B':
+ case 'b':
+ size += 11;
+ break;
+ case 'C':
+ case 'c':
+ size += 12;
+ break;
+ case 'D':
+ case 'd':
+ size += 13;
+ break;
+ case 'E':
+ case 'e':
+ size += 14;
+ break;
+ case 'F':
+ case 'f':
+ size += 15;
+ break;
+ default:
+ // nothing to do
+ break;
+ }
+ if ('\0' == p[1])
+ break;
+ size <<= 4;
+ }
+
+ return size;
}
-void WebClient::handleReadEndSize(const boost_error_code& error, size_t bytes_transferred)
+void WebClient::handleReadChunkSize(const boost_error_code& error, size_t bytes_transferred)
{
- //cout << "HandleReadEndSize" << endl;
-
if (is_cancellation_pending_)
- {
return;
- }
+#if defined DEBUG_WITH_HEXDUMP
+hexdump(boost::asio::buffer_cast<const char*>(response_.data()),
+ bytes_transferred);
+#endif /* DEBUG_WITH_HEXDUMP */
- if (error)
- {
- cout << "Error on receive: " << error.message() << endl;
+ if (error) {
+ cout << "error on receive: " << error.message() << endl;
cancelConnect();
return;
}
- string line = string(boost::asio::buffer_cast<const char*>(response_.data()), bytes_transferred);
+ string chunk_size_line(boost::asio::buffer_cast<const char*>(response_.data()), bytes_transferred);
response_.consume(bytes_transferred);
- if(line.find("0\r\n") >= 0)
- {
- int a = 3;
- }
- read_size_ -= bytes_transferred;
-
- int end_size = -1;
- /*
- if(qi::parse(line.cbegin(), line.cend(), qi::hex[phoenix::ref(end_size) = qi::_1] >> (qi::lit("\r\n") | qi::lit("\n"))))
- {
- if(end_size > 0)
- {
- read_end_size_ = end_size;
- }
- else
- {
- response_body_ += line;
- }
- }
- else
- {
- response_body_ += line;
- }
- */
- response_body_ += line;
-
- read_mode_ = ReadChunkedContent;
- startReadChunkedContent();
-}
-
-void WebClient::handleReadEndLine(const boost_error_code& error, size_t bytes_transferred)
-{
- cout << "HandleReadChunkSize" << endl;
- string raw_line = string(boost::asio::buffer_cast<const char*>(response_.data()), bytes_transferred);
- if(raw_line != "\r\n")
- {
- cout << "End Line:" << raw_line << endl;
- }
- response_.consume(bytes_transferred);
- /*
- int size = response_.size();
- if(size == 0)
- {
+ chunk_size_line.resize(chunk_size_line.length() - 2 /* drop "\r\n" */);
+ size_t chunk_size = hex2size_t(chunk_size_line);
+ if (0 == chunk_size) {
cancelConnect();
return;
}
- */
- startReadChunkedContent();
-}
-void WebClient::handleReadChunkedContent2(const boost_error_code& error, size_t bytes_transferred)
-{
- if (is_cancellation_pending_)
- return;
-
- if (!error)
- {
- string line("");
- /*
- istream is(&response_);
-
- if(!(getline(is, line) && line != "\r"))
- {
- //cout << "-------------------------------------------------------------------" << endl;
- cancelConnect();
- return;
- }
- */
- string aa = string(boost::asio::buffer_cast<const char*>(response_.data()), response_.size());
- line = string(boost::asio::buffer_cast<const char*>(response_.data()), bytes_transferred);
- int position = line.find("\n");
- if(position < 0)
- {
- cout << "1-------------------------------------------------------------------" << endl;
- cancelConnect();
- return;
- }
-
- line = line.substr(0, position + 1);
- response_.consume(line.size());
- /*
- int size = response_.size();
- if(size <= 0)
- {
- //cout << "response_.size() = 0" << endl;
- cancelConnect();
- return;
- }
- */
- if((response_.size() <= 0) && (line == "\r\n"))
- {
- cout << "2-------------------------------------------------------------------" << endl;
- cancelConnect();
- return;
- }
-
- if(!qi::parse(line.cbegin(), line.cend(), qi::hex >> (qi::lit("\r\n") | qi::lit("\n"))))
- {
- // line is chunk size
- response_body_ += line;
- }
- /*
- boost::regex regex("([0-9a-zA-Z]+)\\r\\n");
- boost::smatch smatch;
+ chunk_size += 2; // for trailing CRLF
- if(boost::regex_search(line, smatch, regex))
- {
- int position = smatch.position();
- if(smatch.position() != 0)
- {
- response_body_ += line;
- }
- else
- {
- int a = 3;
- }
- }
- else
- {
- response_body_ += line;
- }
- */
- startReadChunkedContent();
- }
- else
- {
- cout << "Error on receive: " << error.message() << L"\n";
- cancelConnect();
- }
+ boost::asio::async_read(socket_,
+ response_,
+ boost::asio::transfer_exactly(chunk_size),
+ boost::bind(&WebClient::handleReadChunkData, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred));
}
-void WebClient::handleReadChunkedContent(const boost_error_code& error, size_t bytes_transferred)
+void WebClient::handleReadChunkData(const boost_error_code& error, size_t bytes_transferred)
{
if (is_cancellation_pending_)
return;
+#if defined DEBUG_WITH_HEXDUMP
+hexdump(boost::asio::buffer_cast<const char*>(response_.data()),
+ bytes_transferred);
+#endif /* DEBUG_WITH_HEXDUMP */
- if (!error)
- {
- string line("");
- string aa = string(boost::asio::buffer_cast<const char*>(response_.data()), response_.size());
- line = string(boost::asio::buffer_cast<const char*>(response_.data()), bytes_transferred);
- response_.consume(bytes_transferred);
-
- if(line == "\r\n")
- {
- cancelConnect();
- return;
- }
- /*
- if((response_.size() <= 0) && (line == "\r\n"))
- {
- cancelConnect();
- return;
- }
- */
- /*
- if(!qi::parse(line.cbegin(), line.cend(), qi::hex >> (qi::lit("\r\n") | qi::lit("\n"))))
- {
- // line is chunk size
- response_body_ += line;
- }
- */
-
- boost::regex regex("([0-9a-zA-Z]+)\\r\\n");
- boost::smatch smatch;
-
- if(boost::regex_search(line, smatch, regex))
- {
- if(smatch.position() != 0)
- {
- response_body_ += line;
- }
- }
- else
- {
- response_body_ += line;
- }
-
- startReadChunkedContent();
- /*
- boost::asio::async_read_until(socket_, response_, "\n",
- boost::bind(&WebClient::handleReadEndLine, this,
- _1, _2));
- */
- }
- else
- {
- cout << "Error on receive: " << error.message() << L"\n";
- cancelConnect();
- }
-}
-
-void WebClient::handleReadChunkedContent3(const boost_error_code& error, size_t bytes_transferred)
-{
- if (is_cancellation_pending_)
- {
+ if (error) {
+ cout << "error on receive: " << error.message() << endl;
cancelConnect();
- return;
}
- if (!error)
- {
- string line("");
- string aa = string(boost::asio::buffer_cast<const char*>(response_.data()), response_.size());
- line = string(boost::asio::buffer_cast<const char*>(response_.data()), bytes_transferred);
- response_.consume(bytes_transferred);
-
- if(line == "\r\n")
- {
- cancelConnect();
- return;
- }
- /*
- if((response_.size() <= 0) && (line == "\r\n"))
- {
- cancelConnect();
- return;
- }
- */
-
- if(qi::parse(line.cbegin(), line.cend(), qi::hex >> (qi::lit("\r\n") | qi::lit("\n")) >> qi::as_string[*qi::char_][phoenix::ref(response_body_) += qi::_1]))
- {
- // stream response
- cancelConnect();
- return;
- }
- else
- {
- response_body_ += line;
- }
-
- /*
- boost::regex regex("([0-9a-zA-Z]+)\\r\\n");
- boost::smatch smatch;
+ response_body_.append(
+ boost::asio::buffer_cast<const char*>(response_.data()),
+ bytes_transferred - 2 /* drop trailing "\r\n" */);
+ response_.consume(bytes_transferred);
- if(boost::regex_search(line, smatch, regex))
- {
- if(smatch.position() != 0)
- {
- response_body_ += line;
- }
- }
- else
- {
- response_body_ += line;
- }
- */
- //startReadChunkedContent();
-
- boost::asio::async_read_until(socket_, response_, "\n",
- boost::bind(&WebClient::handleReadEndLine, this,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred));
- }
- else
- {
- cout << "Error on receive: " << error.message() << L"\n";
- cancelConnect();
- }
+ // will be trying to read some chunks remaining.
+ startReadChunkedContent();
}
void WebClient::handleReadContent(const boost_error_code& error, size_t bytes_transferred)

0 comments on commit 8da41e0

Please sign in to comment.