#include #include #include "stellar/http.h" #include "http_decoder_private.h" char *safe_dup(const char *str, size_t len) { if (str == NULL || len == 0) { return NULL; } char *dup = CALLOC(char, len + 1); memcpy(dup, str, len); return dup; } int strncasecmp_safe(const char *fix_s1, const char *dyn_s2, size_t fix_n1, size_t dyn_n2) { if (fix_s1 == NULL || dyn_s2 == NULL) { return -1; } if (fix_n1 != dyn_n2) { return -1; } return strncasecmp(fix_s1, dyn_s2, fix_n1); } const char *http_message_type_to_string(enum http_message_type type) { const char *sname = "unknown_msg_type"; switch (type) { case HTTP_MESSAGE_REQ_LINE: sname = "HTTP_MESSAGE_REQ_LINE"; break; case HTTP_MESSAGE_REQ_HEADER: sname = "HTTP_MESSAGE_REQ_HEADER"; break; case HTTP_MESSAGE_REQ_HEADER_END: sname = "HTTP_MESSAGE_REQ_HEADER_END"; break; case HTTP_MESSAGE_REQ_BODY_START: sname = "HTTP_MESSAGE_REQ_BODY_START"; break; case HTTP_MESSAGE_REQ_BODY: sname = "HTTP_MESSAGE_REQ_BODY"; break; case HTTP_MESSAGE_REQ_BODY_END: sname = "HTTP_MESSAGE_REQ_BODY_END"; break; case HTTP_MESSAGE_RES_LINE: sname = "HTTP_MESSAGE_RES_LINE"; break; case HTTP_MESSAGE_RES_HEADER: sname = "HTTP_MESSAGE_RES_HEADER"; break; case HTTP_MESSAGE_RES_HEADER_END: sname = "HTTP_MESSAGE_RES_HEADER_END"; break; case HTTP_MESSAGE_RES_BODY_START: sname = "HTTP_MESSAGE_RES_BODY_START"; break; case HTTP_MESSAGE_RES_BODY: sname = "HTTP_MESSAGE_RES_BODY"; break; case HTTP_MESSAGE_RES_BODY_END: sname = "HTTP_MESSAGE_RES_BODY_END"; break; case HTTP_TRANSACTION_START: sname = "HTTP_TRANSACTION_START"; break; case HTTP_TRANSACTION_END: sname = "HTTP_TRANSACTION_END"; break; default: break; } return sname; } int http_message_type_is_req(struct session *sess, enum http_message_type msg_type) { int is_req_msg = 0; switch (msg_type) { case HTTP_MESSAGE_REQ_LINE: case HTTP_MESSAGE_REQ_HEADER: case HTTP_MESSAGE_REQ_HEADER_END: case HTTP_MESSAGE_REQ_BODY_START: case HTTP_MESSAGE_REQ_BODY: case HTTP_MESSAGE_REQ_BODY_END: is_req_msg = 1; break; case HTTP_MESSAGE_RES_LINE: case HTTP_MESSAGE_RES_HEADER: case HTTP_MESSAGE_RES_HEADER_END: case HTTP_MESSAGE_RES_BODY_START: case HTTP_MESSAGE_RES_BODY: case HTTP_MESSAGE_RES_BODY_END: is_req_msg = 0; break; case HTTP_TRANSACTION_START: case HTTP_TRANSACTION_END: { enum flow_direction cur_dir = session_get_current_flow_direction(sess); if (FLOW_DIRECTION_C2S == cur_dir) { is_req_msg = 1; } else { is_req_msg = 0; } } break; default: assert(0); fprintf(stderr, "unknow message type:%d\n", (int)msg_type); break; } return is_req_msg; } int http_event_is_req(enum http_event event) { switch (event) { case HTTP_EVENT_REQ_INIT: case HTTP_EVENT_REQ_LINE: case HTTP_EVENT_REQ_HDR: case HTTP_EVENT_REQ_HDR_END: case HTTP_EVENT_REQ_BODY_BEGIN: case HTTP_EVENT_REQ_BODY_DATA: case HTTP_EVENT_REQ_BODY_END: case HTTP_EVENT_REQ_END: return 1; break; case HTTP_EVENT_RES_INIT: case HTTP_EVENT_RES_LINE: case HTTP_EVENT_RES_HDR: case HTTP_EVENT_RES_HDR_END: case HTTP_EVENT_RES_BODY_BEGIN: case HTTP_EVENT_RES_BODY_DATA: case HTTP_EVENT_RES_BODY_END: case HTTP_EVENT_RES_END: return 0; break; default: assert(0); fprintf(stderr, "unknow event type:%d\n", (int)event); break; } return -1; } int stellar_session_mq_get_topic_id_reliable(struct stellar *st, const char *topic_name, stellar_msg_free_cb_func *msg_free_cb, void *msg_free_arg) { int topic_id = stellar_mq_get_topic_id(st, topic_name); if (topic_id < 0) { topic_id = stellar_mq_create_topic(st, topic_name, msg_free_cb, msg_free_arg); } return topic_id; } static const unsigned char __g_httpd_hextable[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ 0, 10, 11, 12, 13, 14, 15 /* 0x60 - 0x66 */ }; /* the input is a single hex digit */ #define onehex2dec(x) __g_httpd_hextable[x - '0'] #include // https://github.com/curl/curl/blob/2e930c333658725657b94a923d175c6622e0f41d/lib/urlapi.c void httpd_url_decode(const char *string, size_t length, char *ostring, size_t *olen) { size_t alloc = length; char *ns = ostring; while (alloc) { unsigned char in = (unsigned char)*string; if (('%' == in) && (alloc > 2) && isxdigit(string[1]) && isxdigit(string[2])) { /* this is two hexadecimal digits following a '%' */ in = (unsigned char)(onehex2dec(string[1]) << 4) | onehex2dec(string[2]); string += 3; alloc -= 3; } else { string++; alloc--; } *ns++ = (char)in; } *ns = 0; /* terminate it */ if (olen) /* store output size */ *olen = ns - ostring; return; } int httpd_url_is_encoded(const char *url, size_t len) { for (size_t i = 0; i < len; i++) { if (url[i] == '%') { return 1; } } return 0; } static void httpd_set_tcp_addr(const struct tcphdr *tcph, struct httpd_session_addr *addr, enum flow_direction fdir) { if (FLOW_DIRECTION_C2S == fdir) { addr->sport = tcph->th_sport; addr->dport = tcph->th_dport; } else { addr->sport = tcph->th_dport; addr->dport = tcph->th_sport; } } static void httpd_set_ipv4_addr(const struct ip *ip4h, struct httpd_session_addr *addr, enum flow_direction fdir) { addr->ipver = 4; if (FLOW_DIRECTION_C2S == fdir) { addr->saddr4 = ip4h->ip_src.s_addr; addr->daddr4 = ip4h->ip_dst.s_addr; } else { addr->saddr4 = ip4h->ip_dst.s_addr; addr->daddr4 = ip4h->ip_src.s_addr; } } static void httpd_set_ipv6_addr(const struct ip6_hdr *ip6h, struct httpd_session_addr *addr, enum flow_direction fdir) { addr->ipver = 6; if (FLOW_DIRECTION_C2S == fdir) { memcpy(&addr->saddr6, &ip6h->ip6_src, sizeof(struct in6_addr)); memcpy(&addr->daddr6, &ip6h->ip6_dst, sizeof(struct in6_addr)); } else { memcpy(&addr->saddr6, &ip6h->ip6_dst, sizeof(struct in6_addr)); memcpy(&addr->daddr6, &ip6h->ip6_src, sizeof(struct in6_addr)); } } void httpd_session_get_addr(const struct session *sess, struct httpd_session_addr *addr) { if (sess == NULL || addr == NULL) { return; } enum flow_direction fdir = session_get_current_flow_direction(sess); const struct packet *raw_pkt = session_get_first_packet(sess, fdir); if (NULL == raw_pkt) { addr->ipver = 0; return; } int count = packet_get_layer_count(raw_pkt); for (int i = count - 1; i >= 0; i--) { const struct layer *layer = packet_get_layer_by_idx(raw_pkt, i); if (layer->proto == LAYER_PROTO_TCP) { httpd_set_tcp_addr(layer->hdr.tcp, addr, fdir); } else if (layer->proto == LAYER_PROTO_IPV4) { httpd_set_ipv4_addr(layer->hdr.ip4, addr, fdir); break; } else if (layer->proto == LAYER_PROTO_IPV6) { httpd_set_ipv6_addr(layer->hdr.ip6, addr, fdir); break; } } }