プロキシ環境下でしか動きませんが、使いたい人は勝手に書き換えて下さい。
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<char, 1024> 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;
}