http_status_t read_respond_hdr(void) { acl_assert(vstream_); snprintf(data_.i_addr, sizeof(data_.i_addr), "%s", ACL_VSTREAM_PEER(vstream_)); hdr_res_ = http_hdr_res_new(); int ret = http_hdr_res_get_sync(hdr_res_, vstream_, 60); if (ret < 0) { logger_error("get http respond hdr from %s error %s", data_.i_addr, acl_last_serror()); http_hdr_res_free(hdr_res_); hdr_res_ = NULL; return (HTTP_ERR_READ_HDR); } if (http_hdr_res_parse(hdr_res_) < 0) { logger_error("parse http respond hdr error from %s", data_.i_addr); http_hdr_res_free(hdr_res_); hdr_res_ = NULL; return (HTTP_ERR_INVALID_HDR); } return (HTTP_OK); }
void http_service::win32_proc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { if (lParam == 0) return; HTTP_IPC_DAT* dat = (HTTP_IPC_DAT*) lParam; switch (nMsg - WM_USER) { case HTTP_MSG_HDR: dat->callback->on_hdr(dat->i_addr, dat->i_hdr_res); acl_myfree(dat); break; case HTTP_MSG_DAT: dat->callback->on_body(dat->i_ptr, dat->i_dlen); if (dat->i_ptr && dat->i_dlen > 0) acl_myfree(dat->i_ptr); else { // 调用请求对象的销毁过程 dat->callback->destroy(); if (dat->i_hdr_res) http_hdr_res_free(dat->i_hdr_res); } acl_myfree(dat); break; case HTTP_MSG_ERR: dat->callback->on_error(dat->i_error); // 调用请求对象的销毁过程 dat->callback->destroy(); if (dat->i_hdr_res) http_hdr_res_free(dat->i_hdr_res); acl_myfree(dat); break; default: // 出现了异常消息 logger_error("unknown ipc msg: %d", nMsg); break; } }
virtual void on_message(int nMsg, void* data, int dlen) { acl_assert(dlen == sizeof(HTTP_IPC_DAT)); HTTP_IPC_DAT* dat = (HTTP_IPC_DAT*) data; switch (nMsg) { case HTTP_MSG_HDR: dat->callback->on_hdr(dat->i_addr, dat->i_hdr_res); break; case HTTP_MSG_DAT: dat->callback->on_body(dat->i_ptr, dat->i_dlen); if (dat->i_ptr && dat->i_dlen > 0) acl_myfree(dat->i_ptr); else { // 调用请求对象的销毁过程 dat->callback->destroy(); if (dat->i_hdr_res) http_hdr_res_free(dat->i_hdr_res); this->close(); // 自动触发析构过程 } break; case HTTP_MSG_ERR: dat->callback->on_error(dat->i_error); // 调用请求对象的销毁过程 dat->callback->destroy(); if (dat->i_hdr_res) http_hdr_res_free(dat->i_hdr_res); this->close(); // 自动触发析构过程 break; default: // 出现了异常消息 logger_error("unknown ipc msg: %d", nMsg); break; } }
void http_client::reset(void) { if (buf_) buf_->clear(); if (res_) { // 说明是长连接的第二次请求,所以需要把上次请求的 // 响应头对象及响应体对象释放 acl_assert(hdr_res_); http_res_free(res_); hdr_res_ = NULL; res_ = NULL; } else if (hdr_res_) { // 说明是长连接的第二次请求,因为有可能第一次请求 // 只有响应头,所以仅需要释放上次的响应头对象 http_hdr_res_free(hdr_res_); hdr_res_ = NULL; } if (req_) { acl_assert(hdr_req_); http_req_free(req_); hdr_req_ = NULL; req_ = NULL; } else if (hdr_req_) { http_hdr_req_free(hdr_req_); hdr_req_ = NULL; } if (zstream_) { delete zstream_; zstream_ = NULL; } last_ret_ = -1; body_finish_ = false; chunked_transfer_ = false; }
static void timer_retry(PROBE_SERVER *server) { if (server->stream != NULL) close_stream(server); if (server->res != NULL) { http_res_free(server->res); server->res = NULL; server->hdr_res = NULL; } else if (server->hdr_res != NULL) { http_hdr_res_free(server->hdr_res); server->hdr_res = NULL; } acl_aio_request_timer(server->aio, timer_fn, server, server->probe_inter * 1000000, 0); }
void http_client::do_reply(int status, const char* cmd, const acl::string& body, bool save) { HTTP_HDR_RES* hdr_res = http_hdr_res_static(status); http_hdr_set_keepalive(hdr_req_, hdr_res); http_hdr_put_str(&hdr_res->hdr, "Content-Type", "text/json"); http_hdr_put_int(&hdr_res->hdr, "Content-Length", (int) body.size()); acl::string buf(body.size() + 256); http_hdr_build(&hdr_res->hdr, buf.vstring()); http_hdr_res_free(hdr_res); buf.append(body); if (save) logger("cmd=[%s], reply: [%s]", cmd, buf.c_str()); acl_aio_writen(conn_, buf.c_str(), (int) buf.size()); }
void http_util_free(HTTP_UTIL *http_util) { if ((http_util->flag & HTTP_UTIL_FLAG_SET_DUMP_FILE)) { if (http_util->dump_stream) acl_vstream_close(http_util->dump_stream); } if (http_util->stream) acl_vstream_close(http_util->stream); if (http_util->req_buf) acl_vstring_free(http_util->req_buf); if (http_util->hdr_req) http_hdr_req_free(http_util->hdr_req); if (http_util->http_res) http_res_free(http_util->http_res); else if (http_util->hdr_res) http_hdr_res_free(http_util->hdr_res); acl_myfree(http_util); }
bool http_client::read_response_head(void) { // 以防万一,先清除可能的上次请求的残留的中间数据对象 reset(); if (stream_ == NULL) { logger_error("connect stream not open yet"); disconnected_ = true; return false; } ACL_VSTREAM* vstream = stream_->get_vstream(); if (vstream == NULL) { logger_error("connect stream null"); disconnected_ = true; return false; } hdr_res_ = http_hdr_res_new(); int ret = http_hdr_res_get_sync(hdr_res_, vstream, rw_timeout_); if (ret == -1) { http_hdr_res_free(hdr_res_); hdr_res_ = NULL; disconnected_ = true; return false; } if (http_hdr_res_parse(hdr_res_) < 0) { logger_error("parse response header error"); http_hdr_res_free(hdr_res_); hdr_res_ = NULL; disconnected_ = true; return false; } // 块传输的优先级最高 if (!hdr_res_->hdr.chunked) { // 如果服务器响应时明确指明了长度为 0 则表示不没有数据体 if (hdr_res_->hdr.content_length == 0) { body_finish_ = true; return true; } } const char* ptr = http_hdr_entry_value(&hdr_res_->hdr, "Content-Encoding"); if (ptr && unzip_) { // 目前仅支持 gzip 数据的解压 if (strcasecmp(ptr, "gzip") == 0) { zstream_ = NEW zlib_stream(); if (zstream_->unzip_begin(false) == false) { logger_error("unzip_begin error"); delete zstream_; zstream_ = NULL; } gzip_header_left_ = 10; } else logger_warn("unknown compress format: %s", ptr); } return true; }
void *CHttpClient::DoRequestThread(void* arg) { CHttpClient *phClient = (CHttpClient*) arg; HTTP_HDR_REQ *hdr_req = NULL; HTTP_HDR_RES *hdr_res = NULL; HTTP_RES *http_res = NULL; ACL_VSTRING *buf = acl_vstring_alloc(256); ACL_VSTREAM *server = NULL; const char *pHost = NULL; ACL_VSTREAM *fp = NULL; int ret; UINT nForward = 0; time_t begin = 0; struct timeval begin_tv, end_tv; double time_cost = 0; #undef RETURN #define RETURN(_x_) do \ { \ if (hdr_req) \ http_hdr_req_free(hdr_req); \ if (buf) \ acl_vstring_free(buf); \ if (hdr_res) \ http_hdr_res_free(hdr_res); \ if (http_res) { \ http_res->hdr_res = NULL; \ http_res_free(http_res); \ } \ if (server) \ acl_vstream_close(server); \ if (fp) \ acl_vstream_close(fp); \ gettimeofday(&end_tv, NULL); \ time_cost = stamp_sub(&end_tv, &begin_tv); \ if (time_cost >= 0) \ phClient->ReportTime(time_cost); \ phClient->ReportComplete(); \ return (_x_); \ } while(0) const char *pUrl = phClient->m_sReqUrl.GetString(); hdr_req = http_hdr_req_create(pUrl, phClient->m_bPostMethod ? "POST" : "GET", phClient->m_bHttp11 ? "HTTP/1.1" : "HTTP/1.0"); ASSERT(hdr_req); if (phClient->m_bZip) http_hdr_put_str(&hdr_req->hdr, "Accept-Encoding", "gzip, deflate"); if (phClient->m_bKeepAlive) http_hdr_entry_replace(&hdr_req->hdr, "Connection", "Keep-Alive", 1); if (phClient->m_bPostMethod) http_hdr_put_int(&hdr_req->hdr, "Content-Length", (int) phClient->m_sHttpBody.GetLength()); if (!phClient->m_sAccept.IsEmpty()) http_hdr_put_str(&hdr_req->hdr, "Accept", phClient->m_sAccept.GetString()); if (!phClient->m_sCtype.IsEmpty()) http_hdr_put_str(&hdr_req->hdr, "Content-Type", phClient->m_sCtype.GetString()); if (phClient->m_sHttpHdrAppend.GetLength() > 0) { ACL_ARGV *argv; HTTP_HDR_ENTRY *entry; int i; argv = acl_argv_split(phClient->m_sHttpHdrAppend.GetString(), "\r\n"); for (i = 0; i < argv->argc; i++) { entry = http_hdr_entry_new(argv->argv[i]); if (entry == NULL) continue; http_hdr_append_entry(&hdr_req->hdr, entry); } acl_argv_free(argv); } FORWARD: http_hdr_build_request(hdr_req, buf); pHost = http_hdr_req_host(hdr_req); ASSERT(pHost); phClient->ReportReqHdr(acl_vstring_str(buf), (int) ACL_VSTRING_LEN(buf)); CString serverAddr; if (phClient->m_bUseAddr) serverAddr.Format("%s", phClient->m_sServerAddr); if (serverAddr.GetLength() == 0) serverAddr.Format("%s", pHost); if (strchr(serverAddr.GetString(), ':') == NULL) serverAddr.AppendFormat(":80"); time(&begin); gettimeofday(&begin_tv, NULL); server = acl_vstream_connect(serverAddr.GetString(), ACL_BLOCKING, 10, 10, 4096); if (server == NULL) { CString msg; msg.Format("Connect server(%s) error", serverAddr.GetString()); phClient->ReportErrConnect(msg.GetString()); RETURN (NULL); } if (phClient->m_bLocalSave && fp == NULL) { fp = acl_vstream_fopen(phClient->m_sLocalFile.GetString(), O_WRONLY | O_CREAT | O_TRUNC, 0600, 4096); if (fp == NULL) { acl_msg_error("%s(%d): can't create file(%s)", __FILE__, __LINE__, phClient->m_sLocalFile.GetString()); RETURN (NULL); } } ret = acl_vstream_writen(server, acl_vstring_str(buf), ACL_VSTRING_LEN(buf)); if (ret == ACL_VSTREAM_EOF) { acl_msg_error("%s(%d): write error", __FILE__, __LINE__); RETURN (NULL); } if (phClient->m_bPostMethod && !phClient->m_sHttpBody.IsEmpty()) { if (acl_vstream_writen(server, phClient->m_sHttpBody.GetString(), phClient->m_sHttpBody.GetLength()) == ACL_VSTREAM_EOF) { acl_msg_error("%s(%d): write body error", __FILE__, __LINE__); RETURN (NULL); } } hdr_res = http_hdr_res_new(); if (http_hdr_res_get_sync(hdr_res, server, 10) < 0) { acl_msg_error("%s(%d): get res hdr error", __FILE__, __FILE__, __LINE__); RETURN (NULL); } if (http_hdr_res_parse(hdr_res) < 0) { acl_msg_error("%s(%d): parse hdr_res error", __FILE__, __LINE__); RETURN (NULL); } http_hdr_build(&hdr_res->hdr, buf); phClient->ReportResHdr(acl_vstring_str(buf), (int) ACL_VSTRING_LEN(buf)); phClient->ReportResContentLength((int) hdr_res->hdr.content_length); if (hdr_res->reply_status > 300 && hdr_res->reply_status < 400) { const char* pLocation; HTTP_HDR_REQ *hdr_req_tmp; if (!phClient->m_bForwardAuto) RETURN (NULL); if (nForward++ >= phClient->m_nMaxTry) { acl_msg_error("%s(%d): too many redirect, nForward(%d)", __FILE__, __LINE__, nForward); RETURN (NULL); } pLocation = http_hdr_entry_value(&hdr_res->hdr, "Location"); if (pLocation == NULL || *pLocation == 0) { acl_msg_error("%s(%d): 302 reply with no Location", __FILE__, __LINE__); RETURN (NULL); } hdr_req_tmp = http_hdr_req_rewrite(hdr_req, pLocation); if (hdr_req_tmp == NULL) RETURN (NULL); http_hdr_req_free(hdr_req); http_hdr_res_free(hdr_res); hdr_req = hdr_req_tmp; goto FORWARD; } http_res = http_res_new(hdr_res); while (1) { char tmp_buf[4096]; ret = (int) http_res_body_get_sync2(http_res, server, tmp_buf, sizeof(tmp_buf) - 1); if (ret <= 0) break; phClient->ReportResBody(tmp_buf, ret); phClient->ReportResDownLength((int)(time(NULL) - begin), ret); if (fp != NULL && acl_vstream_writen(fp, tmp_buf, ret) == ACL_VSTREAM_EOF) { acl_msg_error("%s(%d): write to file error", __FILE__, __LINE__); break; } } RETURN (NULL); }
static void get_url(const char *method, const char *url, const char *proxy, const char *dump) { /* 创建 HTTP 请求头 */ HTTP_HDR_REQ *hdr_req = http_hdr_req_create(url, method, "HTTP/1.1"); ACL_VSTREAM *stream; ACL_VSTRING *buf = acl_vstring_alloc(256); HTTP_HDR_RES *hdr_res; HTTP_RES *res; ACL_FILE *fp = NULL; const char *ptr; int ret; /* 输出 HTTP 请求头内容 */ http_hdr_print(&hdr_req->hdr, "---request hdr---"); /* 如果设定代理服务器,则连接代理服务器地址, * 否则使用 HTTP 请求头里指定的地址 */ if (*proxy) acl_vstring_strcpy(buf, proxy); else acl_vstring_strcpy(buf, http_hdr_req_host(hdr_req)); /* 获得远程 HTTP 服务器的连接地址 */ ptr = acl_vstring_memchr(buf, ':'); if (ptr == NULL) acl_vstring_strcat(buf, ":80"); else { int port; ptr++; port = atoi(ptr); if (port <= 0 || port >= 65535) { printf("http server's addr(%s) invalid\n", acl_vstring_str(buf)); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } } /* 连接远程 http 服务器 */ stream = acl_vstream_connect(acl_vstring_str(buf) /* 服务器地址 */, ACL_BLOCKING /* 采用阻塞方式 */, 10 /* 连接超时时间为 10 秒 */, 10 /* 网络 IO 操作超时时间为 10 秒 */, 4096 /* stream 流缓冲区大小为 4096 字节 */); if (stream == NULL) { printf("connect addr(%s) error(%s)\n", acl_vstring_str(buf), acl_last_serror()); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } /* 构建 HTTP 请求头数据 */ http_hdr_build_request(hdr_req, buf); /* 向 HTTP 服务器发送请求 */ ret = acl_vstream_writen(stream, acl_vstring_str(buf), ACL_VSTRING_LEN(buf)); if (ret == ACL_VSTREAM_EOF) { printf("write to server error(%s)\n", acl_last_serror()); acl_vstream_close(stream); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } /* 创建一个 HTTP 响应头对象 */ hdr_res = http_hdr_res_new(); /* 读取 HTTP 服务器响应头*/ ret = http_hdr_res_get_sync(hdr_res, stream, 10 /* IO 超时时间为 10 秒 */); if (ret < 0) { printf("get http reply header error(%s)\n", acl_last_serror()); http_hdr_res_free(hdr_res); acl_vstream_close(stream); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } if (http_hdr_res_parse(hdr_res) < 0) { printf("parse http reply header error\n"); http_hdr_print(&hdr_res->hdr, "--- reply http header ---"); http_hdr_res_free(hdr_res); acl_vstream_close(stream); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } /* 如果需要转储至磁盘则需要先打开文件 */ if (dump != NULL) { fp = acl_fopen(dump, "w+"); if (fp == NULL) printf("open file(%s) error(%s)\n", dump, acl_last_serror()); } /* 如果 HTTP 响应没有数据体则仅输出 HTTP 响应头即可 */ if (hdr_res->hdr.content_length == 0 || (hdr_res->hdr.content_length == -1 && !hdr_res->hdr.chunked && hdr_res->reply_status > 300 && hdr_res->reply_status < 400)) { if (fp) http_hdr_fprint(ACL_FSTREAM(fp), &hdr_res->hdr, "--- reply http header ---"); else http_hdr_fprint(ACL_VSTREAM_OUT, &hdr_res->hdr, "--- reply http header ---"); http_hdr_res_free(hdr_res); acl_vstream_close(stream); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } /* 输出 HTTP 响应头 */ http_hdr_print(&hdr_res->hdr, "--- reply http header ---"); /* 创建 HTTP 响应体对象 */ res = http_res_new(hdr_res); /* 如果有数据体则开始读取 HTTP 响应数据体部分 */ while (1) { http_off_t n; char buf2[4096]; n = http_res_body_get_sync(res, stream, buf2, sizeof(buf2) - 1); if (n <= 0) break; if (fp) { if (acl_fwrite(buf2, (size_t) n, 1, fp) == (size_t) EOF) { printf("write to dump file(%s) error(%s)\n", dump, acl_last_serror()); break; } } else { buf2[n] = 0; printf("%s", buf2); } } if (fp) acl_fclose(fp); http_res_free(res); /* 释放 HTTP 响应对象, hdr_res 会在此函数内部自动被释放 */ acl_vstream_close(stream); /* 关闭网络流 */ acl_vstring_free(buf); /* 释放内存区 */ http_hdr_req_free(hdr_req); /* 释放 HTTP 请求头对象 */ }
// 基类 ipc_request 会自动调用此回调处理请求过程 virtual void run(ipc_client* ipc) { unsigned int nredirect_limit = data_.callback->get_redirect(); unsigned int nredirect = 0; http_status_t ret; while (true) { if ((ret = connect_server()) != HTTP_OK) { report_error(ipc, ret); break; } if ((ret = send_request()) != HTTP_OK) { report_error(ipc, ret); break; } if ((ret = read_respond_hdr()) != HTTP_OK) { report_error(ipc, ret); break; } acl_assert(hdr_res_); // 如果服务器返回的是重定向信息,则进行重定向访问 if ((hdr_res_->reply_status != 301 && hdr_res_->reply_status != 302) || nredirect_limit == 0) { // 发送响应头收到消息给主线程 report(ipc, HTTP_MSG_HDR); // 连续接收响应体并发响应体收到消息给主线程 read_respond_body(ipc); break; } // 开始重定向过程 nredirect++; // 防止重定向次数太多而造成了循环 if (nredirect > nredirect_limit) { report_error(ipc, HTTP_ERR_REDIRECT_MAX); break; } const char* url = http_hdr_entry_value( &hdr_res_->hdr, "Location"); if (url == NULL) { logger_error("redirect Location null"); report_error(ipc, HTTP_ERR_INVALID_HDR); break; } if (data_.callback->redirect(url) == false) { http_hdr_res_free(hdr_res_); hdr_res_ = NULL; report_error(ipc, HTTP_ERR_INVALID_HDR); break; } http_hdr_res_free(hdr_res_); hdr_res_ = NULL; data_.callback->redicrect_reset(); } delete this; }