524 lines
13 KiB
C
524 lines
13 KiB
C
#include "aos_util.h"
|
|
#include "aos_log.h"
|
|
|
|
static const char *g_s_wday[] = {
|
|
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
|
};
|
|
|
|
static const char *g_s_mon[] = {
|
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
|
};
|
|
|
|
static const char g_s_gmt_format[] = "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT";
|
|
|
|
int aos_parse_xml_body(aos_list_t *bc, mxml_node_t **root)
|
|
{
|
|
aos_buf_t *b;
|
|
size_t len;
|
|
|
|
*root = NULL;
|
|
len = (size_t)aos_buf_list_len(bc);
|
|
|
|
{
|
|
int nsize = 0;
|
|
char *buffer = (char*)malloc(sizeof(char)*(len+1));
|
|
memset(buffer, 0, len + 1);
|
|
aos_list_for_each_entry(aos_buf_t, b, bc, node) {
|
|
memcpy(buffer + nsize, (char *)b->pos, aos_buf_size(b));
|
|
nsize += aos_buf_size(b);
|
|
}
|
|
*root = mxmlLoadString(NULL, buffer, MXML_OPAQUE_CALLBACK);
|
|
free(buffer);
|
|
if (NULL == *root) {
|
|
return AOSE_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
return AOSE_OK;
|
|
}
|
|
|
|
int aos_convert_to_gmt_time(char* date, const char* format, apr_time_exp_t *tm)
|
|
{
|
|
int size = apr_snprintf(date, AOS_MAX_GMT_TIME_LEN, format,
|
|
g_s_wday[tm->tm_wday], tm->tm_mday, g_s_mon[tm->tm_mon], 1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
|
if (size >= 0 && size < AOS_MAX_GMT_TIME_LEN) {
|
|
return AOSE_OK;
|
|
} else {
|
|
return AOSE_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
int aos_get_gmt_str_time(char datestr[AOS_MAX_GMT_TIME_LEN])
|
|
{
|
|
int s;
|
|
apr_time_t now;
|
|
char buf[128];
|
|
apr_time_exp_t result;
|
|
|
|
now = apr_time_now();
|
|
if ((s = apr_time_exp_gmt(&result, now)) != APR_SUCCESS) {
|
|
aos_error_log("apr_time_exp_gmt fialure, code:%d %s.", s, apr_strerror(s, buf, sizeof(buf)));
|
|
return AOSE_INTERNAL_ERROR;
|
|
}
|
|
|
|
if ((s = aos_convert_to_gmt_time(datestr, g_s_gmt_format, &result))
|
|
!= AOSE_OK) {
|
|
aos_error_log("aos_convert_to_GMT failure, code:%d.", s);
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
int aos_url_encode(char *dest, const char *src, int maxSrcSize)
|
|
{
|
|
static const char *hex = "0123456789ABCDEF";
|
|
|
|
int len = 0;
|
|
unsigned char c;
|
|
|
|
while (*src) {
|
|
if (++len > maxSrcSize) {
|
|
*dest = 0;
|
|
return AOSE_INVALID_ARGUMENT;
|
|
}
|
|
c = *src;
|
|
if (isalnum(c) || (c == '-') || (c == '_') || (c == '.') || (c == '~')) {
|
|
*dest++ = c;
|
|
} else if (*src == ' ') {
|
|
*dest++ = '%';
|
|
*dest++ = '2';
|
|
*dest++ = '0';
|
|
} else {
|
|
*dest++ = '%';
|
|
*dest++ = hex[c >> 4];
|
|
*dest++ = hex[c & 15];
|
|
}
|
|
src++;
|
|
}
|
|
|
|
*dest = 0;
|
|
|
|
return AOSE_OK;
|
|
}
|
|
|
|
int aos_query_params_to_string(aos_pool_t *p, aos_table_t *query_params, aos_string_t *querystr)
|
|
{
|
|
int rs;
|
|
int pos;
|
|
int len;
|
|
char sep = '?';
|
|
char ebuf[AOS_MAX_QUERY_ARG_LEN*3+1];
|
|
char abuf[AOS_MAX_QUERY_ARG_LEN*6+128];
|
|
int max_len;
|
|
const aos_array_header_t *tarr;
|
|
const aos_table_entry_t *telts;
|
|
aos_buf_t *querybuf;
|
|
|
|
if (apr_is_empty_table(query_params)) {
|
|
return AOSE_OK;
|
|
}
|
|
|
|
max_len = sizeof(abuf)-1;
|
|
querybuf = aos_create_buf(p, 256);
|
|
aos_str_null(querystr);
|
|
|
|
tarr = aos_table_elts(query_params);
|
|
telts = (aos_table_entry_t*)tarr->elts;
|
|
|
|
for (pos = 0; pos < tarr->nelts; ++pos) {
|
|
if ((rs = aos_url_encode(ebuf, telts[pos].key, AOS_MAX_QUERY_ARG_LEN)) != AOSE_OK) {
|
|
aos_error_log("query params args too big, key:%s.", telts[pos].key);
|
|
return AOSE_INVALID_ARGUMENT;
|
|
}
|
|
len = apr_snprintf(abuf, max_len, "%c%s", sep, ebuf);
|
|
if (telts[pos].val != NULL && *telts[pos].val != '\0') {
|
|
if ((rs = aos_url_encode(ebuf, telts[pos].val, AOS_MAX_QUERY_ARG_LEN)) != AOSE_OK) {
|
|
aos_error_log("query params args too big, value:%s.", telts[pos].val);
|
|
return AOSE_INVALID_ARGUMENT;
|
|
}
|
|
len += apr_snprintf(abuf+len, max_len-len, "=%s", ebuf);
|
|
if (len >= AOS_MAX_QUERY_ARG_LEN) {
|
|
aos_error_log("query params args too big, %s.", abuf);
|
|
return AOSE_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
aos_buf_append_string(p, querybuf, abuf, len);
|
|
sep = '&';
|
|
}
|
|
|
|
// result
|
|
querystr->data = (char *)querybuf->pos;
|
|
querystr->len = aos_buf_size(querybuf);
|
|
|
|
return AOSE_OK;
|
|
}
|
|
|
|
void aos_gnome_sort(const char **headers, int size)
|
|
{
|
|
const char *tmp;
|
|
int i = 0, last_highest = 0;
|
|
|
|
while (i < size) {
|
|
if ((i == 0) || apr_strnatcasecmp(headers[i-1], headers[i]) < 0) {
|
|
i = ++last_highest;
|
|
} else {
|
|
tmp = headers[i];
|
|
headers[i] = headers[i - 1];
|
|
headers[--i] = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
const char* aos_http_method_to_string(http_method_e method)
|
|
{
|
|
switch (method) {
|
|
case HTTP_GET:
|
|
return "GET";
|
|
case HTTP_HEAD:
|
|
return "HEAD";
|
|
case HTTP_PUT:
|
|
return "PUT";
|
|
case HTTP_POST:
|
|
return "POST";
|
|
case HTTP_DELETE:
|
|
return "DELETE";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
int aos_base64_encode(const unsigned char *in, int inLen, char *out)
|
|
{
|
|
static const char *ENC =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
char *original_out = out;
|
|
|
|
while (inLen) {
|
|
// first 6 bits of char 1
|
|
*out++ = ENC[*in >> 2];
|
|
if (!--inLen) {
|
|
// last 2 bits of char 1, 4 bits of 0
|
|
*out++ = ENC[(*in & 0x3) << 4];
|
|
*out++ = '=';
|
|
*out++ = '=';
|
|
break;
|
|
}
|
|
// last 2 bits of char 1, first 4 bits of char 2
|
|
*out++ = ENC[((*in & 0x3) << 4) | (*(in + 1) >> 4)];
|
|
in++;
|
|
if (!--inLen) {
|
|
// last 4 bits of char 2, 2 bits of 0
|
|
*out++ = ENC[(*in & 0xF) << 2];
|
|
*out++ = '=';
|
|
break;
|
|
}
|
|
// last 4 bits of char 2, first 2 bits of char 3
|
|
*out++ = ENC[((*in & 0xF) << 2) | (*(in + 1) >> 6)];
|
|
in++;
|
|
// last 6 bits of char 3
|
|
*out++ = ENC[*in & 0x3F];
|
|
in++, inLen--;
|
|
}
|
|
|
|
return (out - original_out);
|
|
}
|
|
|
|
// HMAC-SHA-1:
|
|
//
|
|
// K - is key padded with zeros to 512 bits
|
|
// m - is message
|
|
// OPAD - 0x5c5c5c...
|
|
// IPAD - 0x363636...
|
|
//
|
|
// HMAC(K,m) = SHA1((K ^ OPAD) . SHA1((K ^ IPAD) . m))
|
|
void HMAC_SHA1(unsigned char hmac[20], const unsigned char *key, int key_len,
|
|
const unsigned char *message, int message_len)
|
|
{
|
|
unsigned char kopad[64], kipad[64];
|
|
int i;
|
|
unsigned char digest[APR_SHA1_DIGESTSIZE];
|
|
apr_sha1_ctx_t context;
|
|
|
|
if (key_len > 64) {
|
|
key_len = 64;
|
|
}
|
|
|
|
for (i = 0; i < key_len; i++) {
|
|
kopad[i] = key[i] ^ 0x5c;
|
|
kipad[i] = key[i] ^ 0x36;
|
|
}
|
|
|
|
for ( ; i < 64; i++) {
|
|
kopad[i] = 0 ^ 0x5c;
|
|
kipad[i] = 0 ^ 0x36;
|
|
}
|
|
|
|
apr_sha1_init(&context);
|
|
apr_sha1_update(&context, (const char *)kipad, 64);
|
|
apr_sha1_update(&context, (const char *)message, (unsigned int)message_len);
|
|
apr_sha1_final(digest, &context);
|
|
|
|
apr_sha1_init(&context);
|
|
apr_sha1_update(&context, (const char *)kopad, 64);
|
|
apr_sha1_update(&context, (const char *)digest, 20);
|
|
apr_sha1_final(hmac, &context);
|
|
}
|
|
|
|
unsigned char* aos_md5(aos_pool_t* pool, const char *in, apr_size_t in_len) {
|
|
unsigned char* out;
|
|
apr_md5_ctx_t context;
|
|
|
|
//APR_MD5_DIGESTSIZE: The MD5 digest size, value is 16
|
|
out = aos_palloc(pool, APR_MD5_DIGESTSIZE + 1);
|
|
if (!out) {
|
|
return NULL;
|
|
}
|
|
|
|
if (0 != apr_md5_init(&context)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (0 != apr_md5_update(&context, in, in_len)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (0 != apr_md5_final(out, &context)) {
|
|
return NULL;
|
|
}
|
|
out[APR_MD5_DIGESTSIZE] = '\0';
|
|
return out;
|
|
};
|
|
|
|
int aos_url_decode(const char *in, char *out)
|
|
{
|
|
static const char tbl[256] = {
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
|
|
-1,10,11,12,13,14,15,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,10,11,12,13,14,15,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
|
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1
|
|
};
|
|
char c, v1, v2;
|
|
|
|
if(in != NULL) {
|
|
while((c=*in++) != '\0') {
|
|
if(c == '%') {
|
|
if(!(v1=*in++) || (v1=tbl[(unsigned char)v1])<0 ||
|
|
!(v2=*in++) || (v2=tbl[(unsigned char)v2])<0) {
|
|
*out = '\0';
|
|
return -1;
|
|
}
|
|
c = (v1<<4)|v2;
|
|
} else if (c == '+') {
|
|
c = ' ';
|
|
}
|
|
*out++ = c;
|
|
}
|
|
}
|
|
*out = '\0';
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Convert a string to a long long integer.
|
|
*
|
|
* Ignores `locale' stuff. Assumes that the upper and lower case
|
|
* alphabets and digits are each contiguous.
|
|
*/
|
|
long long aos_strtoll(const char *nptr, char **endptr, int base)
|
|
{
|
|
const char *s;
|
|
/* LONGLONG */
|
|
long long int acc, cutoff;
|
|
int c;
|
|
int neg, any, cutlim;
|
|
|
|
/* endptr may be NULL */
|
|
|
|
#ifdef __GNUC__
|
|
/* This outrageous construct just to shut up a GCC warning. */
|
|
(void) &acc; (void) &cutoff;
|
|
#endif
|
|
|
|
/*
|
|
* Skip white space and pick up leading +/- sign if any.
|
|
* If base is 0, allow 0x for hex and 0 for octal, else
|
|
* assume decimal; if base is already 16, allow 0x.
|
|
*/
|
|
s = nptr;
|
|
do {
|
|
c = (unsigned char) *s++;
|
|
} while (isspace(c));
|
|
if (c == '-') {
|
|
neg = 1;
|
|
c = *s++;
|
|
} else {
|
|
neg = 0;
|
|
if (c == '+')
|
|
c = *s++;
|
|
}
|
|
if ((base == 0 || base == 16) &&
|
|
c == '0' && (*s == 'x' || *s == 'X')) {
|
|
c = s[1];
|
|
s += 2;
|
|
base = 16;
|
|
}
|
|
if (base == 0)
|
|
base = c == '0' ? 8 : 10;
|
|
|
|
/*
|
|
* Compute the cutoff value between legal numbers and illegal
|
|
* numbers. That is the largest legal value, divided by the
|
|
* base. An input number that is greater than this value, if
|
|
* followed by a legal input character, is too big. One that
|
|
* is equal to this value may be valid or not; the limit
|
|
* between valid and invalid numbers is then based on the last
|
|
* digit. For instance, if the range for long longs is
|
|
* [-9223372036854775808..9223372036854775807] and the input base
|
|
* is 10, cutoff will be set to 922337203685477580 and cutlim to
|
|
* either 7 (neg==0) or 8 (neg==1), meaning that if we have
|
|
* accumulated a value > 922337203685477580, or equal but the
|
|
* next digit is > 7 (or 8), the number is too big, and we will
|
|
* return a range error.
|
|
*
|
|
* Set any if any `digits' consumed; make it negative to indicate
|
|
* overflow.
|
|
*/
|
|
cutoff = neg ? LLONG_MIN : LLONG_MAX;
|
|
cutlim = (int)(cutoff % base);
|
|
cutoff /= base;
|
|
if (neg) {
|
|
if (cutlim > 0) {
|
|
cutlim -= base;
|
|
cutoff += 1;
|
|
}
|
|
cutlim = -cutlim;
|
|
}
|
|
for (acc = 0, any = 0;; c = (unsigned char) *s++) {
|
|
if (isdigit(c))
|
|
c -= '0';
|
|
else if (isalpha(c))
|
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
|
else
|
|
break;
|
|
if (c >= base)
|
|
break;
|
|
if (any < 0)
|
|
continue;
|
|
if (neg) {
|
|
if (acc < cutoff || (acc == cutoff && c > cutlim)) {
|
|
any = -1;
|
|
acc = LLONG_MIN;
|
|
errno = ERANGE;
|
|
} else {
|
|
any = 1;
|
|
acc *= base;
|
|
acc -= c;
|
|
}
|
|
} else {
|
|
if (acc > cutoff || (acc == cutoff && c > cutlim)) {
|
|
any = -1;
|
|
acc = LLONG_MAX;
|
|
errno = ERANGE;
|
|
} else {
|
|
any = 1;
|
|
acc *= base;
|
|
acc += c;
|
|
}
|
|
}
|
|
}
|
|
if (endptr != 0)
|
|
/* LINTED interface specification */
|
|
*endptr = (char *)(any ? s - 1 : nptr);
|
|
return (acc);
|
|
}
|
|
|
|
int64_t aos_atoi64(const char *nptr)
|
|
{
|
|
return aos_strtoull(nptr, NULL, 10);
|
|
}
|
|
|
|
unsigned long long aos_strtoull(const char *nptr, char **endptr, int base)
|
|
{
|
|
const char *s;
|
|
unsigned long long acc, cutoff;
|
|
int c;
|
|
int neg, any, cutlim;
|
|
|
|
/*
|
|
* See strtoq for comments as to the logic used.
|
|
*/
|
|
s = nptr;
|
|
do {
|
|
c = (unsigned char) *s++;
|
|
} while (isspace(c));
|
|
if (c == '-') {
|
|
neg = 1;
|
|
c = *s++;
|
|
} else {
|
|
neg = 0;
|
|
if (c == '+')
|
|
c = *s++;
|
|
}
|
|
if ((base == 0 || base == 16) &&
|
|
c == '0' && (*s == 'x' || *s == 'X')) {
|
|
c = s[1];
|
|
s += 2;
|
|
base = 16;
|
|
}
|
|
if (base == 0)
|
|
base = c == '0' ? 8 : 10;
|
|
|
|
cutoff = ULLONG_MAX / (unsigned long long)base;
|
|
cutlim = ULLONG_MAX % (unsigned long long)base;
|
|
for (acc = 0, any = 0;; c = (unsigned char) *s++) {
|
|
if (isdigit(c))
|
|
c -= '0';
|
|
else if (isalpha(c))
|
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
|
else
|
|
break;
|
|
if (c >= base)
|
|
break;
|
|
if (any < 0)
|
|
continue;
|
|
if (acc > cutoff || (acc == cutoff && c > cutlim)) {
|
|
any = -1;
|
|
acc = ULLONG_MAX;
|
|
errno = ERANGE;
|
|
} else {
|
|
any = 1;
|
|
acc *= (unsigned long long)base;
|
|
acc += c;
|
|
}
|
|
}
|
|
if (neg && any > 0)
|
|
#ifdef WIN32
|
|
#pragma warning(disable : 4146)
|
|
#endif
|
|
acc = -acc;
|
|
#ifdef WIN32
|
|
#pragma warning(default : 4146)
|
|
#endif
|
|
if (endptr != 0)
|
|
*endptr = (char *) (any ? s - 1 : nptr);
|
|
return (acc);
|
|
}
|
|
|
|
uint64_t aos_atoui64(const char *nptr)
|
|
{
|
|
return aos_strtoull(nptr, NULL, 10);
|
|
}
|