#include "stdafx.h" #include "http_stream.h" #include "http_client.h" http_client::http_client(acl::aio_handle& handle) : handle_(handle) , refered_(0) , conn_timeout_(5) , rw_timeout_(5) , debug_(false) , redirect_limit_(5) , redirect_count_(0) , url_("/") , keep_alive_(true) , compressed_(false) { } http_client::~http_client(void) { } http_client& http_client::set_addr(const char* addr) { addr_ = addr; return *this; } http_client& http_client::set_timeout(int conn_timeout, int rw_timeout) { conn_timeout_ = conn_timeout; rw_timeout_ = rw_timeout; return *this; } http_client& http_client::set_debug(bool on) { debug_ = on; return *this; } http_client& http_client::set_redirect_limit(int max) { redirect_limit_ = max; return *this; } http_client& http_client::set_url(const char* url) { url_ = url; return *this; } http_client& http_client::set_host(const char* host) { host_ = host; return *this; } http_client& http_client::set_keep_alive(bool yes) { keep_alive_ = yes; return *this; } bool http_client::open(void) { http_stream* conn = new http_stream(handle_, *this); conn->unzip_body(true); acl::http_header& hdr = conn->request_header(); hdr.set_url(url_) .set_host(host_) .accept_gzip(true) .set_keep_alive(keep_alive_); acl::string buf; hdr.build_request(buf); printf("---------------request header-----------------\r\n"); printf("[%s]\r\n", buf.c_str()); if (!conn->open(addr_, conn_timeout_, rw_timeout_)) { delete conn; return false; } ++__aio_refer; // 本对象的引用计数递增 refered_++; return true; } bool http_client::redirect(const char* url) { char domain[256]; unsigned short port; if (!acl::http_utils::get_addr(url, domain, sizeof(domain), &port)) { printf("invalid url=%s\r\n", url); return false; } printf("\r\nredirect to url=%s\r\n\r\n", url); const char http_pref[] = "http://", https_pref[] = "https://"; if (!strncasecmp(url, http_pref, sizeof(http_pref) - 1)) { url += sizeof(http_pref) - 1; } else if (strncasecmp(url, https_pref, sizeof(https_pref) - 1)) { url += sizeof(https_pref) - 1; } const char* slash = strchr(url, '/'); if (slash == NULL) { url = "/"; } else { url = slash; } acl::string addr; addr.format("%s|%d", domain, port); set_addr(addr); set_url(url); set_host(domain); if (open()) { return true; } delete this; return false; } bool http_client::start(void) { if (open()) { return true; } delete this; return false; } void http_client::on_destroy(http_stream* conn) { printf("http_stream will be deleted!\r\n"); delete conn; __destroy++; if (--__aio_refer == 0) { printf("%s: stop aio engine now!\r\n", __FUNCTION__); handle_.stop(); } if (--refered_ == 0) { printf("============== delete http_client =============\r\n"); delete this; } } void http_client::on_connect(http_stream& conn) { printf("--------------- connect server ok ------------\r\n"); acl::string addr; if (conn.get_ns_addr(addr)) { printf(">>>ns server: %s\r\n", addr.c_str()); } __connect_ok++; } void http_client::on_disconnect(http_stream&) { printf("disconnect from server\r\n"); __disconnect++; } void http_client::on_ns_failed(http_stream&) { printf("dns lookup failed\r\n"); __ns_failed++; } void http_client::on_connect_timeout(http_stream&) { printf("connect timeout\r\n"); __connect_timeout++; } void http_client::on_connect_failed(http_stream&) { printf("connect failed\r\n"); __connect_failed++; } bool http_client::on_read_timeout(http_stream&) { printf("read timeout\r\n"); __read_timeout++; return false; } bool http_client::on_http_res_hdr(http_stream&, const acl::http_header& header) { acl::string buf; header.build_response(buf); compressed_ = header.is_transfer_gzip(); __header_ok++; int http_status = header.get_status(); if (debug_) { printf("-----------%s: response header(status=%d)----\r\n", __FUNCTION__, http_status); printf("[%s]\r\n", buf.c_str()); } if (http_status == 301 || http_status == 302) { const char* location = header.get_entry("Location"); if (location == NULL || *location == 0) { printf("Location null\r\n"); return false; } if (++redirect_count_ > redirect_limit_) { printf("\r\nTOO MANY redirect!(%d > %d)\r\n\r\n", redirect_count_, redirect_limit_); return false; } redirect(location); // 返回 false 以使当前连接关闭 return false; } return true; } bool http_client::on_http_res_body(http_stream& conn, char* data, size_t dlen) { if (!debug_) { return true; } bool ret = conn.is_unzip_body(); printf(">>>read body: %ld, unzip_body: %s\r\n", (long) dlen, ret ? "yes" : "no"); (void) write(1, data, dlen); return true; } bool http_client::on_http_res_finish(http_stream&, bool success) { printf("\r\n---------------response over----------------\r\n"); printf("http finish: keep_alive=%s, success=%s\r\n", keep_alive_ ? "true" : "false", success ? "ok" : "failed"); __success++; return keep_alive_; }