309 lines
7.9 KiB
C++
309 lines
7.9 KiB
C++
#include <string.h>
|
|
#include <assert.h>
|
|
#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 <ctype.h>
|
|
// 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;
|
|
}
|
|
}
|
|
} |