static void incr_string(ACL_VSTRING *vp, int len, const char* s, int debug) { int i; printf("max: %ld, len: %ld, cnt: %ld\r\n", (long) vp->maxlen, vp->vbuf.len, vp->vbuf.cnt); for (i = 0; i < len; i++) ACL_VSTRING_ADDCH(vp, 'x'); if (s && *s) acl_vstring_sprintf_append(vp, "%s", s); else ACL_VSTRING_TERMINATE(vp); if (debug) printf("[%s]\r\n", acl_vstring_str(vp)); printf("strlen: %ld, ACL_VSTRING_LEN: %ld, max: %ld\r\n", (long) strlen(acl_vstring_str(vp)), (long) ACL_VSTRING_LEN(vp), (long) vp->maxlen); printf("Enter any key to continue ...\r\n\r\n"); getchar(); ACL_VSTRING_RESET(vp); ACL_VSTRING_TERMINATE(vp); }
static int chunked_trailer(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) { HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; char *data; int dlen; sbuf = acl_aio_gets_peek(astream); if (sbuf == NULL) return (0); data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ctx->body_len += dlen; if (strcmp(data, "\r\n") == 0 || strcmp(data, "\n") == 0) { DISABLE_READ(astream); if ((dlen = notify(HTTP_CHAT_OK, data, dlen, arg)) < 0) return (-1); return (1); } if (notify(HTTP_CHAT_CHUNK_TRAILER, data, dlen, arg) < 0) return (-1); return (0); }
void http_error_reply(HTTP_CLIENT *http_client, int status, const char *msg) { static __thread ACL_VSTRING *__buf = NULL; const ACL_VSTRING *str; const char *ptr; struct iovec iov[2]; if (__buf == NULL) { __buf = acl_vstring_alloc(256); acl_pthread_atexit_add(__buf, free_buf); } ptr = http_tmpl_title(status); str = http_tmpl_get(status); if (msg == NULL || *msg == 0) msg = acl_vstring_str(str); acl_vstring_sprintf(__buf, reply_error_fmt, status, ptr); iov[0].iov_base = acl_vstring_str(__buf); iov[0].iov_len = ACL_VSTRING_LEN(__buf); iov[1].iov_base = (char*) msg; iov[1].iov_len = strlen(msg); acl_aio_writev(http_client->stream, iov, 2); }
const char* json_node::tag_name(void) const { if (node_me_->ltag && ACL_VSTRING_LEN(node_me_->ltag) > 0) return (acl_vstring_str(node_me_->ltag)); else return (NULL); }
const char* xml_node::id(void) const { if (node_->id && ACL_VSTRING_LEN(node_->id) > 0) return acl_vstring_str(node_->id); else return NULL; }
const char* json_node::get_text(void) const { if (node_me_->text && ACL_VSTRING_LEN(node_me_->text) > 0) return acl_vstring_str(node_me_->text); else return NULL; }
bool json_node::set_tag(const char* name) { if (name == NULL || *name == 0) return false; if (node_me_->ltag == NULL || ACL_VSTRING_LEN(node_me_->ltag) == 0) return false; acl_vstring_strcpy(node_me_->ltag, name); return true; }
static const char *xml_parse_meta_text(ACL_XML *xml, const char *data) { int ch; if (LEN(xml->curr_node->text) == 0) { SKIP_SPACE(data); } while ((ch = *data) != 0) { if (xml->curr_node->quote) { if (ch == xml->curr_node->quote) { xml->curr_node->quote = 0; } ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } else if (IS_QUOTE(ch)) { if (xml->curr_node->quote == 0) { xml->curr_node->quote = ch; } ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } else if (ch == '<') { xml->curr_node->nlt++; ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } else if (ch == '>') { if (xml->curr_node->nlt == 0) { char *last; size_t off; data++; xml->curr_node->status = ACL_XML_S_MEND; if ((xml->curr_node->flag & ACL_XML_F_META_QM) == 0) break; last = acl_vstring_end(xml->curr_node->text) - 1; if (last < STR(xml->curr_node->text) || *last != '?') break; off = ACL_VSTRING_LEN(xml->curr_node->text) - 1; if (off == 0) break; ACL_VSTRING_AT_OFFSET(xml->curr_node->text, off); ACL_VSTRING_TERMINATE(xml->curr_node->text); xml_meta_attr(xml->curr_node); break; } xml->curr_node->nlt--; ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } else { ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } data++; } ACL_VSTRING_TERMINATE(xml->curr_node->text); return (data); }
static void b64_decode(const char *ptr) { ACL_VSTRING *str = acl_vstring_alloc(1); const char *p; #define DECODE(b,x,l) { \ if (acl_vstring_base64_decode((b),(x),(l)) == 0) { \ printf("bad base64 encoded string: %s\r\n", (x)); \ exit (1); \ } \ } DECODE(str, ptr, strlen(ptr)); p = acl_vstring_str(str); printf(">>>decode result:|%s|\n>>>orignal str: {%s}, len: %d\n", p, ptr, (int) ACL_VSTRING_LEN(str)); b64_encode(p); printf("len: %d, %d\n", (int) ACL_VSTRING_LEN(str), (int) strlen(p)); acl_vstring_free(str); }
static int chunked_data(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) { HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; char *data; int dlen, ret; if (ctx->chunked) { ret = (int) HTTP_LEN_ROUND(ctx); sbuf = acl_aio_readn_peek(astream, ret); } else if (ctx->hdr->content_length <= 0) { sbuf = acl_aio_read_peek(astream); } else { ret = (int) HTTP_LEN_ROUND(ctx); sbuf = acl_aio_readn_peek(astream, ret); } if (sbuf == NULL) { return (0); } data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ctx->body_len += dlen; ctx->read_cnt += dlen; if (ctx->chunk_len > 0 && ctx->read_cnt >= ctx->chunk_len) { if (!ctx->chunked) { /* xxx: 禁止连续读 */ DISABLE_READ(astream); if (notify(HTTP_CHAT_OK, data, dlen, arg) < 0) return (-1); return (1); } if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) return (-1); /* 设置标志位开始读取块数据体的分隔行数据 */ ctx->status = CHAT_S_CHUNK_SEP; return (0); } if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) return (-1); return (0); }
static int hdr_can_read(ACL_ASTREAM *astream, void *context) { HTTP_CHAT_CTX *ctx = (HTTP_CHAT_CTX *) context; HTTP_HDR *hdr = ctx->hdr; HTTP_HDR_NOTIFY notify = ctx->notify.hdr_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; char *data; int dlen; int ret; while (1) { if ((ret = acl_aio_can_read(astream)) == ACL_VSTREAM_EOF) { notify(HTTP_CHAT_ERR_IO, arg); return (-1); } else if (ret == 0) { break; } sbuf = acl_aio_gets_nonl_peek(astream); if (sbuf == NULL) { break; } data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ret = hdr_ready(hdr, data, dlen); switch (ret) { case HTTP_CHAT_CONTINUE: break; case HTTP_CHAT_OK: DISABLE_READ(astream); if (notify(ret, arg) < 0) { return (0); } return (0); default: DISABLE_READ(astream); (void) notify(ret, arg); return (0); } } acl_aio_enable_read(astream, hdr_can_read, ctx); return (0); }
const char *str_name_mask_opt(ACL_VSTRING *buf, const char *context, const NAME_MASK *table, int mask, int flags) { const char *myname = "name_mask"; const NAME_MASK *np; int len; static ACL_VSTRING *my_buf = 0; int delim = (flags & NAME_MASK_COMMA ? ',' : (flags & NAME_MASK_PIPE ? '|' : ' ')); if (buf == 0) { if (my_buf == 0) my_buf = acl_vstring_alloc(1); buf = my_buf; } ACL_VSTRING_RESET(buf); for (np = table; mask != 0; np++) { if (np->name == 0) { if (flags & NAME_MASK_FATAL) { acl_msg_fatal("%s: unknown %s bit in mask: 0x%x", myname, context, mask); } else if (flags & NAME_MASK_RETURN) { acl_msg_warn("%s: unknown %s bit in mask: 0x%x", myname, context, mask); return (0); } else if (flags & NAME_MASK_NUMBER) { acl_vstring_sprintf_append(buf, "0x%x%c", mask, delim); } break; } if (mask & np->mask) { mask &= ~np->mask; acl_vstring_sprintf_append(buf, "%s%c", np->name, delim); } } if ((len = (int) ACL_VSTRING_LEN(buf)) > 0) acl_vstring_truncate(buf, len - 1); ACL_VSTRING_TERMINATE(buf); return (STR(buf)); }
static void vstring_extend(ACL_VBUF *bp, int incr) { const char *myname = "vstring_extend"; unsigned used = bp->ptr - bp->data; int new_len; ACL_VSTRING *vp = (ACL_VSTRING *) bp->ctx; if (vp->maxlen > 0 && (int) ACL_VSTRING_LEN(vp) > vp->maxlen) acl_msg_warn("%s(%d), %s: reached the maxlen: %d", __FILE__, __LINE__, myname, vp->maxlen); /* * Note: vp->vbuf.len is the current buffer size (both on entry and on * exit of this routine). We round up the increment size to the buffer * size to avoid silly little buffer increments. With really large * strings we might want to abandon the length doubling strategy, and go * to fixed increments. */ /* new_len = bp->len + (bp->len > incr ? bp->len : incr); */ /* below come from redis-server/sds.c/sdsMakeRoomFor, which can * avoid memory double growing too large --- 2015.2.2, zsx */ new_len = bp->len + incr; if (new_len < MAX_PREALLOC) new_len *= 2; else new_len += MAX_PREALLOC; if (vp->slice) bp->data = (unsigned char *) acl_slice_pool_realloc( __FILE__, __LINE__, vp->slice, bp->data, new_len); else if (vp->dbuf) { const unsigned char *data = bp->data; bp->data = (unsigned char *) acl_dbuf_pool_alloc( vp->dbuf, new_len); memcpy(bp->data, data, used); } else bp->data = (unsigned char *) acl_myrealloc(bp->data, new_len); bp->len = new_len; bp->ptr = bp->data + used; bp->cnt = bp->len - used; }
static int chunked_data_endl(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) { HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; char *data; int dlen; sbuf = acl_aio_gets_peek(astream); if (sbuf == NULL) return (0); data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ctx->body_len += dlen; if (notify(HTTP_CHAT_CHUNK_DATA_ENDL, data, dlen, arg) < 0) return (-1); ctx->status = CHAT_S_CHUNK_HDR; return (0); }
static int hdr_gets_ready(ACL_ASTREAM *astream, void *context, char *data, int dlen) { HTTP_CHAT_CTX *ctx = (HTTP_CHAT_CTX *) context; HTTP_HDR *hdr = ctx->hdr; HTTP_HDR_NOTIFY notify = ctx->notify.hdr_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; int ret; while (1) { ret = hdr_ready(hdr, data, dlen); switch (ret) { case HTTP_CHAT_CONTINUE: break; case HTTP_CHAT_OK: acl_aio_del_read_hook(astream, hdr_gets_ready, context); if (notify(ret, arg) < 0) { return (-1); } return (0); default: acl_aio_del_read_hook(astream, hdr_gets_ready, context); (void) notify(ret, arg); return (-1); } sbuf = acl_aio_gets_nonl_peek(astream); if (sbuf == NULL) break; data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); } acl_aio_gets_nonl(astream); return (0); }
int http_util_req_open(HTTP_UTIL *http_util) { const char *myname = "http_util_req_open"; int ret; /* 连接远程 http 服务器 */ http_util->stream = acl_vstream_connect(http_util->server_addr, ACL_BLOCKING /* 采用阻塞方式 */, http_util->conn_timeout /* 连接超时时间 */, http_util->rw_timeout /* 网络 IO 操作超时时间 */, 4096 /* stream 流缓冲区大小为 4096 字节 */); if (http_util->stream == NULL) { acl_msg_error("%s(%d): connect %s error(%s)", myname, __LINE__, http_util->server_addr, acl_last_serror()); return (-1); } /* 构建 HTTP 请求头数据 */ http_hdr_build_request(http_util->hdr_req, http_util->req_buf); /* 向 HTTP 服务器发送请求 */ ret = acl_vstream_writen(http_util->stream, acl_vstring_str(http_util->req_buf), ACL_VSTRING_LEN(http_util->req_buf)); if (ret == ACL_VSTREAM_EOF) { acl_msg_error("%s(%d): send request to server(%s) error(%s)", myname, __LINE__, http_util->server_addr, acl_last_serror()); return (-1); } return (0); }
static void notify_thread(void *arg) { const char *myname = "notify_thread"; WARN_INFO *info = (WARN_INFO*) arg; ACL_VSTREAM *client; ACL_VSTRING *buf; int ret; buf = acl_vstring_alloc(256); acl_vstring_sprintf(buf, "PROC=%s|PID=%d|RCPT=%s|info=%s\r\n", info->path, info->pid, info->notify_recipients, info->desc); client = acl_vstream_connect(info->notify_addr, ACL_BLOCKING, 60, 60, 1024); if (client == NULL) { acl_msg_error("%s(%d): connect %s error, info(%s)", myname, __LINE__, info->notify_addr, acl_vstring_str(buf)); acl_vstring_free(buf); warn_info_free(info); return; } /* 禁止将该句柄传递给子进程 */ acl_close_on_exec(ACL_VSTREAM_SOCK(client), ACL_CLOSE_ON_EXEC); ret = acl_vstream_writen(client, acl_vstring_str(buf), ACL_VSTRING_LEN(buf)); if (ret == ACL_VSTREAM_EOF) acl_msg_error("%s(%d): write to notify server error, info(%s)", myname, __LINE__, acl_vstring_str(buf)); else acl_msg_info("%s(%d): notify ok!", myname, __LINE__); acl_vstream_close(client); acl_vstring_free(buf); warn_info_free(info); }
static int chunked_hdr(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) { HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; char *data, *ptr; int dlen; sbuf = acl_aio_gets_peek(astream); if (sbuf == NULL) return (0); data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ctx->body_len += dlen; ctx->read_cnt = 0; ptr = strchr(data, ' '); if (ptr) *ptr = 0; ctx->chunk_len = strtoul(data, NULL, 16); if (ptr) *ptr = ' '; if (notify(HTTP_CHAT_CHUNK_HDR, data, dlen, arg) < 0) return (-1); if (ctx->chunk_len == 0) { ctx->status = CHAT_S_CHUNK_TAL; return (0); } ctx->status = CHAT_S_CHUNK_DAT; return (0); }
static void test_string(ACL_FILE_HANDLE fd, ssize_t max, int debug) { ACL_VSTRING *vp = acl_vstring_mmap_alloc(fd, 1, max); const char *s = "hello world!"; printf("-------------------------------------------------------\r\n"); incr_string(vp, max - 1, NULL, debug); printf("-------------------------------------------------------\r\n"); incr_string(vp, max - 1 - strlen(s), s, debug); printf("-------------------------------------------------------\r\n"); incr_string(vp, max, NULL, debug); printf("-------------------------------------------------------\r\n"); incr_string(vp, max + 2, NULL, debug); printf("-------------------------------------------------------\r\n"); acl_vstring_strcat(vp, s); incr_string(vp, max - strlen(s) - 1, NULL, debug); printf("-------------------------------------------------------\r\n"); acl_vstring_strcat(vp, s); incr_string(vp, max, NULL, debug); printf("-------------------------------------------------------\r\n"); acl_vstring_strcat(vp, s); incr_string(vp, max + 10, NULL, debug); printf(">>>[%s]\r\n", acl_vstring_str(vp)); printf(">>>len: %ld, %ld, %p, %p\r\n", (long) strlen(acl_vstring_str(vp)), (long) ACL_VSTRING_LEN(vp), acl_vstring_str(vp), acl_vstring_end(vp)); acl_vstring_free(vp); }
static int sms_send(ACL_VSTREAM *client, const char *phone, const char *proc, int pid, const char *info, const char *ip) { ACL_VSTRING *buf = acl_vstring_alloc(256); ACL_XML *xml = acl_xml_alloc(); char res[1024]; int ret; acl_vstring_sprintf(buf, "<send_sms phone=\"%s\" message=\"proc:%s, pid:%d, ip:%s, info:%s\" />", phone, proc, pid, ip, info); if (acl_vstream_writen(client, acl_vstring_str(buf), ACL_VSTRING_LEN(buf)) == ACL_VSTREAM_EOF) { acl_msg_error("write to sms server error, msg: %s", acl_vstring_str(buf)); acl_vstring_free(buf); return (-1); } acl_msg_info(">>send: %s", acl_vstring_str(buf)); acl_vstring_free(buf); while (1) { ret = acl_vstream_read(client, res, sizeof(res) - 1); if (ret == ACL_VSTREAM_EOF) return (-1); res[ret] = 0; acl_xml_parse(xml, res); if (acl_xml_is_complete(xml, "send_sms")) { acl_msg_info("send ok!(%s)", res); break; } } return (0); }
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); }
#include <stdio.h> #include <stdlib.h> static char *html = \ "<html>\r\n" "<head> <title> 'hello world!' </title> </head>\r\n" "<body> \"hello && world!\" </body>\r\n" "</html>\r\n"; int main(int argc acl_unused, char *argv[] acl_unused) { ACL_VSTRING *buf1 = acl_vstring_alloc(32); ACL_VSTRING *buf2 = acl_vstring_alloc(32); acl_xml_encode(html, buf1); printf(">>> xml encode: len(%d)\n%s",(int) ACL_VSTRING_LEN(buf1), acl_vstring_str(buf1)); printf("------------------------------------------\n"); acl_xml_decode(acl_vstring_str(buf1), buf2); printf(">>> xml decode: len(%d)\n%s", (int) ACL_VSTRING_LEN(buf2), acl_vstring_str(buf2)); printf("------------------------------------------\n"); ACL_VSTRING_RESET(buf1); ACL_VSTRING_RESET(buf2); acl_html_encode(html, buf1); printf(">>> html encode: len(%d)\n%s", (int) ACL_VSTRING_LEN(buf1), acl_vstring_str(buf1)); printf("------------------------------------------\n");
static int chunked_data(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) { HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf = NULL; char *data; int dlen, ret; if (ctx->chunked) { ret = (int) HTTP_LEN_ROUND(ctx); sbuf = acl_aio_readn_peek(astream, ret); } else if (ctx->hdr->content_length <= 0) sbuf = acl_aio_read_peek(astream); else { ret = (int) HTTP_LEN_ROUND(ctx); if (ret <= 0) { /* 说明本次 HTTP 数据已经读完且遇到对方关闭 * 或对方发来了多余的数据,所以需要返回 -1 */ DISABLE_READ(astream); if (notify(HTTP_CHAT_OK, NULL, 0, arg) < 0) return (-1); return (-1); } else sbuf = acl_aio_readn_peek(astream, ret); } if (sbuf == NULL) return (0); data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ctx->body_len += dlen; ctx->read_cnt += dlen; if (ctx->chunk_len > 0 && ctx->read_cnt >= ctx->chunk_len) { if (!ctx->chunked) { /* 如果读到完了整块数据且非 CHUNK 传输, * 则认为读完 HTTP 响应 */ /* xxx: 禁止连续读 */ DISABLE_READ(astream); if (notify(HTTP_CHAT_OK, data, dlen, arg) < 0) return (-1); return (1); } /* 对于 chunk 传输,读完本数据块 */ if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) return (-1); /* 设置标志位开始读取块数据体的分隔行数据 */ ctx->status = CHAT_S_CHUNK_SEP; return (0); } if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) return (-1); return (0); }
ACL_VSTRING *tok822_externalize(ACL_VSTRING *vp, TOK822 *tree, int flags) { ACL_VSTRING *tmp; TOK822 *tp; ssize_t start = 0; TOK822 *addr = 0; ssize_t addr_len = 0; /* * Guard against a Sendmail buffer overflow (CERT advisory CA-2003-07). * The problem was that Sendmail could store too much non-address text * (comments, phrases, etc.) into a static 256-byte buffer. * * When the buffer fills up, fixed Sendmail versions remove comments etc. * and reduce the information to just <$g>, which expands to <address>. * No change is made when an address expression (text separated by * commas) contains no address. This fix reportedly also protects * Sendmail systems that are still vulnerable to this problem. * * Postfix takes the same approach, grudgingly. To avoid unnecessary damage, * Postfix removes comments etc. only when the amount of non-address text * in an address expression (text separated by commas) exceeds 250 bytes. * * With Sendmail, the address part of an address expression is the * right-most <> instance in that expression. If an address expression * contains no <>, then Postfix guarantees that it contains at most one * non-comment string; that string is the address part of the address * expression, so there is no ambiguity. * * Finally, we note that stress testing shows that other code in Sendmail * 8.12.8 bluntly truncates ``text <address>'' to 256 bytes even when * this means chopping the <address> somewhere in the middle. This is a * loss of control that we're not entirely comfortable with. However, * unbalanced quotes and dangling backslash do not seem to influence the * way that Sendmail parses headers, so this is not an urgent problem. */ #define MAX_NONADDR_LENGTH 250 #define RESET_NONADDR_LENGTH { \ start = ACL_VSTRING_LEN(vp); \ addr = 0; \ addr_len = 0; \ } #define ENFORCE_NONADDR_LENGTH do { \ if (addr && (ssize_t) ACL_VSTRING_LEN(vp) - addr_len > start + MAX_NONADDR_LENGTH) \ strip_address(vp, start, addr->head); \ } while(0) if (flags & TOK822_STR_WIPE) ACL_VSTRING_RESET(vp); if (flags & TOK822_STR_TRNC) RESET_NONADDR_LENGTH; for (tp = tree; tp; tp = tp->next) { switch (tp->type) { case ',': if (flags & TOK822_STR_TRNC) ENFORCE_NONADDR_LENGTH; ACL_VSTRING_ADDCH(vp, tp->type); ACL_VSTRING_ADDCH(vp, (flags & TOK822_STR_LINE) ? '\n' : ' '); if (flags & TOK822_STR_TRNC) RESET_NONADDR_LENGTH; continue; /* * XXX In order to correctly externalize an address, it is not * sufficient to quote individual atoms. There are higher-level * rules that say when an address localpart needs to be quoted. * We wing it with the quote_822_local() routine, which ignores * the issue of atoms in the domain part that would need quoting. */ case TOK822_ADDR: addr = tp; tmp = acl_vstring_alloc(100); tok822_internalize(tmp, tp->head, TOK822_STR_TERM); addr_len = ACL_VSTRING_LEN(vp); quote_822_local_flags(vp, acl_vstring_str(tmp), QUOTE_FLAG_8BITCLEAN | QUOTE_FLAG_APPEND); addr_len = ACL_VSTRING_LEN(vp) - addr_len; acl_vstring_free(tmp); break; case TOK822_ATOM: case TOK822_COMMENT: acl_vstring_strcat(vp, acl_vstring_str(tp->vstr)); break; case TOK822_QSTRING: ACL_VSTRING_ADDCH(vp, '"'); tok822_copy_quoted(vp, acl_vstring_str(tp->vstr), "\"\\\r\n"); ACL_VSTRING_ADDCH(vp, '"'); break; case TOK822_DOMLIT: ACL_VSTRING_ADDCH(vp, '['); tok822_copy_quoted(vp, acl_vstring_str(tp->vstr), "\\\r\n"); ACL_VSTRING_ADDCH(vp, ']'); break; case TOK822_STARTGRP: ACL_VSTRING_ADDCH(vp, ':'); break; case '<': if (tp->next && tp->next->type == '>') { addr = tp; addr_len = 0; } ACL_VSTRING_ADDCH(vp, '<'); break; default: if (tp->type >= TOK822_MINTOK) acl_msg_panic("tok822_externalize: unknown operator %d", tp->type); ACL_VSTRING_ADDCH(vp, tp->type); } if (tok822_append_space(tp)) ACL_VSTRING_ADDCH(vp, ' '); } if (flags & TOK822_STR_TRNC) ENFORCE_NONADDR_LENGTH; if (flags & TOK822_STR_TERM) ACL_VSTRING_TERMINATE(vp); return (vp); }
static ACL_MSGIO *__ipc_listener = NULL; static char __ipc_addr[256]; static module_service_main_fn __service_callback = NULL; /* 某个线程服务实例接收到一个新的远程客户端连接请求 */ static int msg_ipc_accept(int msg_type acl_unused, ACL_MSGIO *mio acl_unused, const ACL_MSGIO_INFO *info, void *arg) { IPC_CTX ctx; ACL_VSTREAM *stream; ACL_ASTREAM *client; SERVICE *service = (SERVICE*) arg; memcpy(&ctx, acl_vstring_str(info->body.buf), ACL_VSTRING_LEN(info->body.buf)); /* 打开异步流 */ stream = acl_vstream_fdopen(ctx.fd, O_RDWR, var_cfg_aio_buf_size, 0, ACL_VSTREAM_TYPE_SOCK); client = acl_aio_open(ctx.aio, stream); /* 开始处理该客户端连接 */ __service_callback(service, client); return (0); } /* 单线程实例非阻塞处理过程 */ static void *service_thread(void *arg) {
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 请求头对象 */ }
int mac_parse(const char *value, MAC_PARSE_FN action, char *context) { const char *myname = "mac_parse"; ACL_VSTRING *buf = acl_vstring_alloc(1); /* result buffer */ const char *vp; /* value pointer */ const char *pp; /* open_paren pointer */ const char *ep; /* string end pointer */ static char open_paren[] = "({"; static char close_paren[] = ")}"; int level; int status = 0; #define SKIP(start, var, cond) \ for (var = start; *var && (cond); var++); acl_debug(DEBUG_MAC, 2) ("%s: %s", myname, value); for (vp = value; *vp;) { if (*vp != '$') { /* ordinary character */ ACL_VSTRING_ADDCH(buf, *vp); vp += 1; } else if (vp[1] == '$') { /* $$ becomes $ */ ACL_VSTRING_ADDCH(buf, *vp); vp += 2; } else { /* found bare $ */ if (ACL_VSTRING_LEN(buf) > 0) MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context); vp += 1; pp = open_paren; if (*vp == *pp || *vp == *++pp) { /* ${x} or $(x) */ level = 1; vp += 1; for (ep = vp; level > 0; ep++) { if (*ep == 0) { acl_msg_warn("truncated macro reference: \"%s\"", value); status |= MAC_PARSE_ERROR; break; } if (*ep == *pp) level++; if (*ep == close_paren[pp - open_paren]) level--; } if (status & MAC_PARSE_ERROR) break; acl_vstring_strncat(buf, vp, level > 0 ? ep - vp : ep - vp - 1); vp = ep; } else { /* plain $x */ SKIP(vp, ep, ACL_ISALNUM(*ep) || *ep == '_'); acl_vstring_strncat(buf, vp, ep - vp); vp = ep; } if (ACL_VSTRING_LEN(buf) == 0) { status |= MAC_PARSE_ERROR; acl_msg_warn("empty macro name: \"%s\"", value); break; } MAC_PARSE_ACTION(status, MAC_PARSE_EXPR, buf, context); } } if (ACL_VSTRING_LEN(buf) > 0 && (status & MAC_PARSE_ERROR) == 0) MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context); /* * Cleanup. */ acl_vstring_free(buf); return (status); }
static int vstring_extend(ACL_VBUF *bp, ssize_t incr) { const char *myname = "vstring_extend"; ssize_t used = (ssize_t) (bp->ptr - bp->data), new_len; ACL_VSTRING *vp = (ACL_VSTRING *) bp; if (vp->maxlen > 0 && (ssize_t) ACL_VSTRING_LEN(vp) >= vp->maxlen) { ACL_VSTRING_AT_OFFSET(vp, vp->maxlen - 1); ACL_VSTRING_TERMINATE(vp); acl_msg_warn("%s(%d), %s: overflow maxlen: %ld, %ld", __FILE__, __LINE__, myname, (long) vp->maxlen, (long) ACL_VSTRING_LEN(vp)); bp->flags |= ACL_VBUF_FLAG_EOF; return ACL_VBUF_EOF; } #ifdef ACL_WINDOWS if (bp->fd == ACL_FILE_INVALID && (bp->flags & ACL_VBUF_FLAG_FIXED)) #else if (bp->fd < 0 && (bp->flags & ACL_VBUF_FLAG_FIXED)) #endif { acl_msg_warn("%s(%d), %s: can't extend fixed buffer", __FILE__, __LINE__, myname); return ACL_VBUF_EOF; } /* * Note: vp->vbuf.len is the current buffer size (both on entry and on * exit of this routine). We round up the increment size to the buffer * size to avoid silly little buffer increments. With really large * strings we might want to abandon the length doubling strategy, and * go to fixed increments. */ #ifdef INCR_NO_DOUBLE /* below come from redis-server/sds.c/sdsMakeRoomFor, which can * avoid memory double growing too large --- 2015.2.2, zsx */ new_len = bp->len + incr; if (new_len < MAX_PREALLOC) new_len *= 2; else new_len += MAX_PREALLOC; #else new_len = bp->len + (bp->len > incr ? bp->len : incr); #endif if (vp->maxlen > 0 && new_len > vp->maxlen) new_len = vp->maxlen; if (vp->slice) bp->data = (unsigned char *) acl_slice_pool_realloc( __FILE__, __LINE__, vp->slice, bp->data, new_len); else if (vp->dbuf) { const unsigned char *data = bp->data; bp->data = (unsigned char *) acl_dbuf_pool_alloc( vp->dbuf, new_len); memcpy(bp->data, data, used); acl_dbuf_pool_free(vp->dbuf, data); } else if (bp->fd != ACL_FILE_INVALID) { #ifdef ACL_UNIX acl_off_t off = new_len - 1; if (acl_lseek(bp->fd, off, SEEK_SET) != (acl_off_t) off) acl_msg_fatal("lseek failed: %s, off: %lld", acl_last_serror(), off); if (acl_file_write(bp->fd, "\0", 1, 0, NULL, NULL) == ACL_VSTREAM_EOF) { acl_msg_fatal("write error: %s", acl_last_serror()); } #endif } else bp->data = (unsigned char *) acl_myrealloc(bp->data, new_len); bp->len = new_len; bp->ptr = bp->data + used; bp->cnt = bp->len - used; return 0; }
static int mac_expand_callback(int type, ACL_VSTRING *buf, char *ptr) { MAC_EXP *mc = (MAC_EXP *) ptr; int lookup_mode; const char *text; char *cp, *pp = NULL; int ch; ssize_t len; size_t size; /* * Sanity check. */ if (mc->level++ > 100) { acl_msg_warn("unreasonable macro call nesting: \"%s\"", acl_vstring_str(buf)); mc->status |= MAC_PARSE_ERROR; } if (mc->status & MAC_PARSE_ERROR) return (mc->status); /* * $Name etc. reference. * * In order to support expansion of lookup results, we must save the lookup * result. We use the input buffer since it will not be needed anymore. */ if (type == MAC_PARSE_EXPR) { /* * Look for the ? or : delimiter. In case of a syntax error, return * without doing damage, and issue a warning instead. */ for (cp = acl_vstring_str(buf); /* void */ ; cp++) { if ((ch = *cp) == 0) { lookup_mode = MAC_EXP_MODE_USE; break; } if (ch == '?' || ch == ':') { *cp++ = 0; lookup_mode = MAC_EXP_MODE_TEST; break; } if (!ACL_ISALNUM(ch) && ch != '_') { acl_msg_warn("macro name syntax error: \"%s\"", acl_vstring_str(buf)); mc->status |= MAC_PARSE_ERROR; return (mc->status); } } /* * Look up the named parameter. */ text = mc->lookup(acl_vstring_str(buf), lookup_mode, mc->context, &pp, &size); /* * Perform the requested substitution. */ switch (ch) { case '?': if (text != 0 && *text != 0) mac_parse(cp, mac_expand_callback, (char *) mc); break; case ':': if (text == 0 || *text == 0) mac_parse(cp, mac_expand_callback, (char *) mc); break; default: if (text == 0) { mc->status |= MAC_PARSE_UNDEF; } else if (*text == 0) { /* void */ ; } else if (mc->flags & MAC_EXP_FLAG_RECURSE) { acl_vstring_strcpy(buf, text); mac_parse(acl_vstring_str(buf), mac_expand_callback, (char *) mc); } else { len = (int) ACL_VSTRING_LEN(mc->result); acl_vstring_strcat(mc->result, text); if (mc->filter) { cp = acl_vstring_str(mc->result) + len; while (*(cp += strspn(cp, mc->filter))) *cp++ = '_'; } } break; } } /* * Literal text. */ else { acl_vstring_strcat(mc->result, acl_vstring_str(buf)); } mc->level--; if (pp) free(pp); return (mc->status); }