2012/10/11

Recent entries from same category

  1. RapidJSON や simdjson よりも速いC言語から使えるJSONライブラリ「yyjson」
  2. コメントも扱える高機能な C++ 向け JSON パーサ「jsoncpp」
  3. C++ で flask ライクなウェブサーバ「clask」書いた。
  4. C++ 用 SQLite3 ORM 「sqlite_orm」が便利。
  5. zsh で PATH に相対パスを含んだ場合にコマンドが補完できないのは意図的かどうか。

タイトルなげーーーーーーーーーーー!
プロキシ環境下でしか動きませんが、使いたい人は勝手に書き換えて下さい。
boost::bind 使わずラムダだけでやってんの、オレオレルールだから気にした奴は負け。
#define _WIN32_WINNT 0x0501
#include <iostream>
#include <string>
#include <sstream>
#include <system_error>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/regex.hpp>
#include <boost/foreach.hpp>
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
#include <boost/property_tree/json_parser.hpp>

using namespace boost::asio;
using namespace boost::asio::ip;
using namespace boost::property_tree;
using namespace boost::system;

int
main(int argc, char* argv[]) {
  if (argc == 1) {
    std::cerr << "usage: " << argv[0] << " [words]" << std::endl;
    return -1;
  }

  // リクエストする URL を作る
  std::string get_url =
    "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=";

  for (int i = 1; i < argc; i++) {
    std::string arg = argv[i];
    BOOST_FOREACH(auto c, arg) {
      if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
          (c >= '0' && c <= '9') ||
          c == '-' || c == '_' || c == '.' || c == '~') {
        get_url += c;
      } else if (c == ' ') {
        get_url += '+';
      } else {
        std::stringstream ss;
        ss << "%" << std::hex << std::setw(2) <<
          std::setfill('0') << (int) (c & 0xff);
        get_url += ss.str();
      }
    }
  }

  // HTTP_PROXY 環境変数からホスト名とポート番号を得る
  std::string http_proxy = std::getenv("HTTP_PROXY");
  boost::regex pattern("^(?:http://)?([^/]+):([0-9]+)");
  boost::match_results<std::string::const_iterator> it;
  if (!regex_search(http_proxy, it, pattern)) {
    std::cerr << "プロキシを使っていません" << std::endl;
    return -1;
  }

  io_service service;
  tcp::resolver resolver(service);

  // ホスト名から名前解決を行う
  tcp::resolver::query resolver_query(
    std::string(it[1].first, it[1].second), // ホスト名
    std::string(it[2].first, it[2].second)  // ポート番号
  );

  std::string data;
  resolver.async_resolve(
    resolver_query,
    [&](const error_code& ec, tcp::resolver::iterator it) {
      if (ec) {
        std::cerr << ec.message() << std::endl;
      } else {
        // プロキシに接続する
        tcp::socket socket(service);
        socket.async_connect(
          it->endpoint(),
          [&](const error_code& ec) {
            if (ec) {
              std::cerr << ec.message() << std::endl;
            } else {
              // プロキシに GET 命令を送信する
              std::string query = "GET ";
              query += get_url;
              query += " HTTP/1.0\r\n\r\n";

              async_write(
                socket,
                buffer(query.c_str(), query.size()),
                [&](const error_code& ec, std::size_t len) {
                  if (ec) {
                    std::cerr << ec.message() << std::endl;
                  } else {
                    boost::array<char1024> buf;
                    std::stringstream ss;
                    // HTTP/1.0 なので切断までループ
                    while (socket.is_open()) {
                      socket.async_read_some(
                        buffer(buf),
                        [&](const error_code& ec, std::size_t len) {
                          if (ec) {
                            socket.close();
                          } else if (len == 0) {
                            socket.close();
                          } else {
                            ss << std::string(buf.data(), len);
                            buf.assign(0);
                          }
                        });
                      service.run_one();
                    }
                    data = ss.str();
                    // ヘッダを取り除く
                    std::size_t pos = data.find("\r\n\r\n");
                    if (pos != std::string::npos) {
                      data = data.substr(pos + 4);
                    }
                  }
                });
              service.run_one();
            }
          });
        service.run_one();
      }
    });
  service.run_one();

  if (!data.empty()) {
    // 結果で得られた JSON をパースする
    std::stringstream ss(data);
    ptree pt;
    read_json(ss, pt);

    if (pt.get<int>("responseStatus") == 200) {
      // 結果配列でループしながら表示
      ptree& results = pt.get_child("responseData.results");
      BOOST_FOREACH(const ptree::value_type& result, results) {
        std::string url = result.second.get<std::string>("url");
        std::string title = result.second.get<std::string>("titleNoFormatting");
        std::cout << url << std::endl << "  " << title << std::endl;
      }
    }
  }
  return 0;
}
Posted at by