📄 mms_util.c
字号:
{"image/gif", "gif"},
{"image/bmp", "bmp"},
{"image/vnd.wap.wbmp", "wbmp"},
{"image/x-bmp", "bmp"},
{"image/x-wmf", "bmp"},
{"image/vnd.wap.wpng", "png"},
{"image/x-up-wpng", "png"},
{"audio/mpeg", "mp3"},
{"audio/wav", "wav"},
{"audio/basic", "au"},
{"audio/amr", "amr"},
{"audio/x-amr", "amr"},
{"audio/amr-wb", "amr"},
{"audio/midi", "mid"},
{"audio/sp-midi", "mid"},
{"application/smil", "smil"},
{"application/vnd.wap.mms-message", "mms"},
{"application/java-archive", "jar"},
{"video/3gpp", "3gp2"},
{"video/3gpp", "3gp"},
{NULL, NULL}
};
Octstr *filename2content_type(char *fname)
{
char *p = strrchr(fname, '.');
int i;
if (p)
for (i = 0; exts[i].file_ext; i++)
if (strcasecmp(p+1, exts[i].file_ext) == 0)
return octstr_imm(exts[i].ctype);
return octstr_imm("application/octet-stream");
}
char *content_type2file_ext(Octstr *ctype)
{
int i;
for (i = 0; exts[i].file_ext; i++)
if (octstr_str_case_compare(ctype, exts[i].ctype) == 0)
return exts[i].file_ext;
return "dat";
}
static int fetch_url_with_auth(HTTPCaller *c, int method, Octstr *url, List *request_headers,
Octstr *body, Octstr *auth_hdr, List **reply_headers, Octstr **reply_body);
int mms_url_fetch_content(int method, Octstr *url, List *request_headers,
Octstr *body, List **reply_headers, Octstr **reply_body)
{
int status = 0;
Octstr *furl = NULL;
if (octstr_search(url, octstr_imm("data:"), 0) == 0) {
int i = octstr_search_char(url, ',',0);
Octstr *ctype = (i >= 0) ? octstr_copy(url, 5, i-5) : octstr_create("text/plain; charset=us-ascii");
Octstr *data = (i >= 0) ? octstr_copy(url, i+1, octstr_len(url)) : octstr_duplicate(url);
Octstr *n = NULL, *h = NULL;
if (octstr_len(ctype) == 0)
octstr_append_cstr(ctype, "text/plain; charset=us-ascii");
split_header_value(ctype, &n, &h);
if (h) {
List *ph = get_value_parameters(h);
Octstr *v = NULL;
if (ph && (v = http_header_value(ph, octstr_imm("base64"))) != NULL) { /* has base64 item */
Octstr *p = NULL;
octstr_base64_to_binary(data);
http_header_remove_all(ph, "base64");
octstr_destroy(ctype);
if (gwlist_len(ph) > 0) {
p = make_value_parameters(ph);
ctype = octstr_format("%S; %S",
n,p);
octstr_destroy(p);
} else
ctype = octstr_format("%S", n);
}
if (ph)
http_destroy_headers(ph);
octstr_destroy(v);
octstr_destroy(h);
}
octstr_destroy(n);
*reply_body = data;
*reply_headers = http_create_empty_headers();
http_header_add(*reply_headers, "Content-Type", octstr_get_cstr(ctype));
octstr_destroy(ctype);
status = HTTP_OK;
} else if (octstr_search(url, octstr_imm("file://"), 0) == 0) {
char *file = octstr_get_cstr(url) + 6;
Octstr *ctype = filename2content_type(file);
Octstr *data = octstr_read_file(file);
*reply_body = data;
*reply_headers = http_create_empty_headers();
http_header_add(*reply_headers, "Content-Type", octstr_get_cstr(ctype));
status = data ? HTTP_OK : HTTP_NOT_FOUND;
octstr_destroy(ctype);
} else {
HTTPCaller *c = http_caller_create();
http_start_request(c, method, url, request_headers, body, 1, NULL, NULL);
if (http_receive_result_real(c, &status, &furl, reply_headers, reply_body,1) == NULL)
status = -1;
if (status == HTTP_UNAUTHORIZED) {
Octstr *v = http_header_value(*reply_headers, octstr_imm("WWW-Authenticate"));
status = fetch_url_with_auth(c, method, url, request_headers, body, v,
reply_headers, reply_body);
octstr_destroy(v);
}
http_caller_destroy(c);
}
octstr_destroy(furl);
return status;
}
Octstr *get_stripped_param_value(Octstr *value, Octstr *param)
{
Octstr *x = http_get_header_parameter(value, param);
if (x != NULL &&
octstr_get_char(x, 0) == '"' &&
octstr_get_char(x, octstr_len(x) - 1) == '"') {
octstr_delete(x, 0, 1);
octstr_delete(x, octstr_len(x) - 1, 1);
}
return x;
}
#define HASHLEN 16
static Octstr *make_url(HTTPURLParse *h);
/* Fetch a url with authentication as necessary. */
static int fetch_url_with_auth(HTTPCaller *c, int method, Octstr *url, List *request_headers,
Octstr *body, Octstr *auth_hdr, List **reply_headers, Octstr **reply_body)
{
Octstr *xauth_value = auth_hdr ? octstr_duplicate(auth_hdr) : octstr_create("");
Octstr *domain = NULL, *nonce = NULL, *opaque = NULL, *algo = NULL, *auth_type = NULL, *x;
Octstr *realm = NULL, *xurl = NULL;
Octstr *cnonce = NULL;
char *nonce_count = "00000001";
Octstr *A1 = NULL, *A2 = NULL, *rd = NULL;
List *qop = NULL, *l = NULL;
int i, status = HTTP_UNAUTHORIZED, has_auth = 0, has_auth_int = 0;
HTTPURLParse *h = parse_url(url);
unsigned char mdbuf[1+HASHLEN*4], *xs;
char *m_qop = NULL;
time_t t = time(NULL);
/* Check that there is a username and password in the URL! */
if (h == NULL || h->user == NULL || octstr_len(h->user) == 0)
goto done;
/* First we get the auth type: */
if ((i = octstr_search_char(xauth_value, ' ', 0)) < 0) {
warning(0, "Mal-formed WWW-Authenticate header (%s) received while fetching %s!",
octstr_get_cstr(xauth_value), url ? octstr_get_cstr(url) : "");
status = -1;
goto done;
}
auth_type = octstr_copy(xauth_value, 0, i);
octstr_delete(xauth_value, 0, i+1);
if (octstr_str_case_compare(auth_type, "Basic") == 0) {
status = HTTP_UNAUTHORIZED; /* suported by default by GWLIB so if we get here, means bad passwd. */
goto done;
} /* else digest. */
/* Put back some fake data so what we have can be parsed easily. */
if ((l = http_header_split_auth_value(xauth_value)) != NULL) {
Octstr *x = gwlist_get(l, 0);
octstr_insert(x, octstr_imm("_none; "), 0); /* make it easier to parse. */
octstr_destroy(xauth_value);
xauth_value = octstr_duplicate(x);
gwlist_destroy(l, (gwlist_item_destructor_t *)octstr_destroy);
} else
warning(0, "Mal-formed Digest header (%s) while fetching (%s)!",
octstr_get_cstr(xauth_value), url ? octstr_get_cstr(url) : "");
realm = get_stripped_param_value(xauth_value, octstr_imm("realm"));
domain = get_stripped_param_value(xauth_value, octstr_imm("domain"));
nonce = get_stripped_param_value(xauth_value, octstr_imm("nonce"));
opaque = get_stripped_param_value(xauth_value, octstr_imm("opaque"));
algo = get_stripped_param_value(xauth_value, octstr_imm("algorithm"));
if ((x = get_stripped_param_value(xauth_value, octstr_imm("qop"))) != NULL) {
int i;
qop = octstr_split(x, octstr_imm(","));
octstr_destroy(x);
for (i = 0; i<gwlist_len(qop); i++) { /* find qop options. */
Octstr *s = gwlist_get(qop, i);
if (!s) continue;
if (octstr_str_case_compare(s, "auth") == 0)
has_auth = 1;
else if (octstr_str_case_compare(s, "auth-int") == 0)
has_auth_int = 1;
}
}
/* from here on, libssl is required. */
#ifdef HAVE_LIBSSL
if (qop ||
(algo != NULL && octstr_str_case_compare(algo, "MD5-sess") == 0)) {
unsigned char *x = MD5((void *)&t, sizeof t, (void *)mdbuf);
cnonce = octstr_create_from_data((void *)x, 4);
octstr_binary_to_hex(cnonce,0);
}
/* Make A1 */
x = octstr_format("%S:%S:%S",
h->user, realm, h->pass ? h->pass : octstr_imm(""));
xs = MD5((void *)octstr_get_cstr(x), octstr_len(x), (void *)mdbuf);
A1 = octstr_create_from_data((char *)xs, HASHLEN);
octstr_destroy(x);
if (algo != NULL && octstr_str_case_compare(algo, "MD5-sess") == 0) {
x = octstr_format("%S:%S:%S",
A1, nonce, cnonce);
xs = MD5((void *)octstr_get_cstr(x), octstr_len(x), (void *)mdbuf);
octstr_destroy(A1);
A1 = octstr_create_from_data((char *)xs, HASHLEN);
octstr_destroy(x);
}
octstr_binary_to_hex(A1,0);
/* Make A2. */
x = octstr_format("%s:%S",
http_method2name(method),
h->path);
if (qop != NULL && has_auth_int && !has_auth) { /* if qop, and qop=auth-int */
Octstr *y;
m_qop = "auth-int";
xs = MD5((void *)octstr_get_cstr(body), octstr_len(body), (void *)mdbuf);
y = octstr_create_from_data((char *)xs, HASHLEN);
octstr_binary_to_hex(y,0);
octstr_append_char(x, ':');
octstr_append(x, y);
octstr_destroy(y);
} else if (qop)
m_qop = "auth";
xs = MD5((void *)octstr_get_cstr(x), octstr_len(x), (void *)mdbuf);
A2 = octstr_create_from_data((char *)xs, HASHLEN);
octstr_destroy(x);
octstr_binary_to_hex(A2,0);
/* Finally make the digest response */
if (qop)
x = octstr_format("%S:%S:%s:%S:%s:%S",
A1, nonce, nonce_count, cnonce,
m_qop, A2);
else
x = octstr_format("%S:%S:%S", A1, nonce, A2);
xs = MD5((void *)octstr_get_cstr(x), octstr_len(x), (void *)mdbuf);
octstr_destroy(x);
rd = octstr_create_from_data((char *)xs, HASHLEN);
octstr_binary_to_hex(rd, 0);
/* make the header value */
x = octstr_format("Digest username=\"%S\", realm=\"%S\", response=\"%S\", nonce=\"%S\", uri=\"%S\"",
h->user, realm, rd, nonce, h->path);
if (opaque)
octstr_format_append(x, ", opaque=\"%S\"", opaque);
if (cnonce)
octstr_format_append(x, ", cnonce=\"%S\", nc=%s", cnonce, nonce_count);
if (m_qop)
octstr_format_append(x,", qop=%s", m_qop);
if (algo)
octstr_format_append(x,", algorithm=%S", algo);
http_header_remove_all(request_headers, "Authorization");
http_header_add(request_headers, "Authorization", octstr_get_cstr(x));
octstr_destroy(x);
/* Remove username, password, then remake URL */
if (h->user) octstr_destroy(h->user);
h->user = NULL;
if (h->pass) octstr_destroy(h->pass);
h->pass = NULL;
xurl = make_url(h);
x = NULL;
http_start_request(c, method, xurl, request_headers, body, 1, NULL, NULL);
if (http_receive_result_real(c, &status, &x, reply_headers, reply_body,1) == NULL)
status = -1;
if (x)
octstr_destroy(x);
#else
mdbuf[0] = 0; /* keep the compiler quiet. */
error(0, "Digest authentication requested on url (%s), but SSL not compiled!",
octstr_get_cstr(url));
#endif
done:
octstr_destroy(xauth_value);
octstr_destroy(realm);
octstr_destroy(domain);
octstr_destroy(nonce);
octstr_destroy(opaque);
octstr_destroy(algo);
octstr_destroy(xurl);
octstr_destroy(cnonce);
gwlist_destroy(qop, (gwlist_item_destructor_t *)octstr_destroy);
if (h)
http_urlparse_destroy(h);
return status;
}
static Octstr *make_url(HTTPURLParse *h)
{
Octstr *url = octstr_duplicate(h->scheme);
if (h->user) {
octstr_format_append(url, "%S", h->user);
if (h->pass)
octstr_format_append(url, ":%S", h->pass);
octstr_format_append(url, "@");
}
octstr_format_append(url, "%S:%d%S", h->host, h->port, h->path);
if (h->query)
octstr_format_append(url, "?%S", h->query);
if (h->fragment)
octstr_format_append(url, "#%S", h->fragment);
return url;
}
static int is_separator_char(int c)
{
switch (c) {
case '(':
case ')':
case '<':
case '>':
case '@':
case ',':
case ';':
case ':':
case '\\':
case '"':
case '/':
case '[':
case ']':
case '?':
case '=':
case '{':
case '}':
case 32: /* SP */
case 9: /* HT */
return 1;
default:
return 0;
}
}
/* Is this char part of a 'token' as defined by HTTP? */
static int is_token_char(int c)
{
return c >= 32 && c < 127 && !is_separator_char(c);
}
/* Is this string a 'token' as defined by HTTP? */
int mms_is_token(Octstr *token)
{
return octstr_len(token) > 0 &&
octstr_check_range(token, 0, octstr_len(token), is_token_char);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -