18 Eylül 2017 Pazartesi

asio ve http header

Giriş
http cevabı şuna benzer. İlk kısım \r\n\r\n ile biter ve buna header diyorum. Örnekte GMT'ten sonraki \r\n ve boş satır yani. Geri kalan alan ise xml, binary vs. gibi birşey olabilir.
HTTP/1.1 200 OK
Connection: close
Content-Length: 42
Server: C/1.1
Date: Thu, 24 Nov 2016 07:47:27 GMT

{"Out":[1],"In":[1,2,3,4,5,6]}
Bu satırları parse etmek için şöyle yaparız.

1. Tüm header satırlarını okuruz. Şöyle yaparız.
asio::streambuf buf;
// Get till all the headers
asio::read_until (socket, buf, "\r\n\r\n");
2. Cevabı kontrol etmek için şöyle yaparız.
2.1 Http sürüm bilgisini okuruz.
// Check that response is OK. 
std::istream istream (&buf);
std::string http_version;
istream >> http_version;
std::cout << "Version : " << http_version << std::endl;
2.2 Status numarasını okuruz
unsigned int status_code;
istream >> status_code;
Eğer status kodu 200 değil hata kabul edebiliriz.
if (status_code != 200) {
  std::cerr << "response did not returned 200 but " << status_code;
  return -1; 
}
2.3 Status mesajını okuruz
std::string status_message;
std::getline (istream, status_message);
Buraya kadar olan her şeyi tek seferde yapmak istersek şöyle yaparız.
boost::asio::streambuf buf;

std::istream response_stream (&buf);
response_stream >> http_version;
response_stream >> status_code;
response_stream >> status_message;
Bu kod gereksiz ancak eğer status mesajını kontrol etmek istersek şöyle yaparız.
if (!istream || status_message.substr(0, 5) != "HTTP/")
{
  std::cout << "Invalid response\n";
  return 1;
}
3. Tüm header'ları okuruz
Tüm header'ları okumak için şöyle yaparız
//read the headers.
std::string header;
while (std::getline (istream, header) && header != "\r") {
  std::cout << "H: " << header << std::endl;
}
header'ı key-value olarak ayırmak için şöyle yaparız.
header.resize(header.size() - 1);
std::size_t found = header.find(':');
if (found != std::string::npos) {
  key = header.substr(0, found);
  value = header.substr(found + 2);
  headers_[key] = value;
}
4. istream'ı boşaltmak için şöyle yaparız.
// Ignore the remaining additional '\r\n' after the header
std::getline (istream, header);
5. Header'dan sonraki alanı okuruz.
Örnek
Header'dan sonrası xml ise şöyle yaparız.
std::string const response = ...;
auto headersEnd = response.find("\r\n\r\n");
if (std::string::npos == headersEnd)
  throw std::runtime_error("Malformed response");

std::istringstream iss(response.substr(headersEnd+4));
boost::property_tree::ptree ntree;
read_xml(iss, ntree);
Örnek 
Şöyle yaparız.
boost::asio::streambuf response;

// Read until EOF, writing data to output as we go.
boost::system::error_code ec;
while (boost::asio::read(socket, response,
            boost::asio::transfer_at_least(1), ec))
  std::cout << &response;
if (error != boost::asio::error::eof)
  throw boost::system::system_error(error);
}
catch (std::exception& e)
{
  std::cout << "Exception: " << e.what() << "\n";
}
Örnek
Şöyle yaparız.
std::string chunk_siz_str;

// Read the Chunk size
asio::read_until(socket, buf, "\r\n");
std::getline (istream, chunk_siz_str);
std::cout << "CS : " << chunk_siz_str << std::endl;
Veya geri kalan herşeyi okumak için şöyle yaparız.
std::ostringstream ostringstream_content;
if (buf.size() > 0) {
  ostringstream_content << &response;
}

std::error_code error;
while (true) {
  size_t n = asio::read(socket, response, asio::transfer_at_least(1), error);
  if (!error) {
    if (n) {
      ostringstream_content << &response;
    }
  } 

  if (error == asio::error::eof) {
    break;
  }
  if (error) {
    return -1; //throw boost::system::system_error(error);
  }
}

Hiç yorum yok:

Yorum Gönder