#ifdef XP_WIN32
#define _MBCS
#include <windows.h>
#include <mbctype.h>
#endif
#include "util.h"
#include "pool.h"
#ifdef XP_WIN32
static PRBool _getfullpathname = -
1;
#endif
static inline
int allow_dbcs_uri()
{
return PR_TRUE;
}
#ifdef XP_WIN32
void set_fullpathname(PRBool b)
{
_getfullpathname = b;
}
#endif
NSAPI_PUBLIC int util_uri_is_evil_internal(
const char *t,
int allow_tilde,
int allow_dot_dir)
{
#ifdef XP_WIN32
int flagDbcsUri = allow_dbcs_uri();
#endif
PRBool flagEmptySegment =
PR_FALSE;
int x;
for (x =
0; t[x]; ++x) {
if (t[x] ==
'/') {
if (flagEmptySegment)
return 1;
#ifdef XP_WIN32
if (t[x+
1] ==
'/' && x !=
0)
#else
if (t[x+
1] ==
'/')
#endif
return 1;
if (t[x+
1] ==
';')
flagEmptySegment =
PR_TRUE;
if (t[x+
1] ==
'.') {
if (t[x+
2] ==
'\0')
return 1;
if (!allow_dot_dir && (t[x+
2] ==
'/' || t[x+
2] ==
';'))
return 1;
if (t[x+
2] ==
'.' && (t[x+
3] ==
'/' || t[x+
3] ==
';' || t[x+
3] ==
'\0'))
return 1;
}
}
#ifdef XP_WIN32
if (!allow_tilde && (t[x] ==
'~')) {
return 1;
}
if ((t[x] ==
':') && x >
1) {
return 1;
}
if (((t[x] ==
'.') || (t[x] ==
' ')) &&
((t[x+
1] ==
';') || (t[x+
1] ==
'/') || (t[x+
1] ==
'\0')))
{
return 1;
}
if (flagDbcsUri && t[x+
1] && IsDBCSLeadByte(t[x])) x++;
#endif
}
return 0;
}
NSAPI_PUBLIC int util_uri_is_evil(
const char *t)
{
return util_uri_is_evil_internal(t,
0,
0);
}
#ifdef XP_WIN32
NSAPI_PUBLIC
int util_uri_unescape_and_normalize(
pool_handle_t *pool,
char *s,
char *unnormalized)
{
if(!(util_uri_unescape_strict(s)))
return 0;
if (unnormalized) strcpy(unnormalized, s);
if (_getfullpathname == -
1)
_getfullpathname = (_getmbcp() !=
0);
if(_getfullpathname && strcmp(s,
"*") && (*s ==
'/' ) ) {
char *pzAbsPath =
NULL;
int pathlen =
0;
int len =
0;
int ret =
0;
if(!(pzAbsPath = util_canonicalize_uri(pool, s, strlen(s),
NULL))) {
return 0;
}
char *pzPath = (
char *)
MALLOC(
MAX_PATH +
1);
char *pzFilename =
NULL;
if(!(ret = GetFullPathName(pzAbsPath,
MAX_PATH, pzPath, &pzFilename)) || ( ret >
MAX_PATH)){
FREE(pzAbsPath);
FREE(pzPath);
return 0;
}
len = strlen(pzAbsPath);
pathlen = strlen( pzPath );
if ( pzAbsPath[len-
1] ==
'/' && pzPath[pathlen-
1] !=
'\\')
strcat( pzPath,
"\\");
FREE(pzAbsPath);
pzFilename = strchr(pzPath,
'\\');
if(!pzFilename) {
FREE(pzPath);
return 0;
}
strcpy(s, pzFilename);
FREE(pzPath);
}
util_uri_normalize_slashes(s);
return 1;
}
#endif
void util_uri_normalize_slashes(
char *s)
{
#ifdef XP_WIN32
int flagDbcsUri = allow_dbcs_uri();
while (*s) {
if (*s ==
'\\') {
*s =
'/';
}
else if (flagDbcsUri && s[
1] && IsDBCSLeadByte(s[
0])) {
s++;
}
s++;
}
#endif
}
NSAPI_PUBLIC char *util_uri_escape(
char *od,
const char *s)
{
int flagDbcsUri = allow_dbcs_uri();
char *d;
if (!od)
od = (
char *)
MALLOC((strlen(s)*
3) +
1);
d = od;
while (*s) {
if (strchr(
"% ?#:+&*\"''<>\r\n", *s)) {
util_sprintf(d,
"%%%02x", (
unsigned char)*s);
++s; d +=
3;
}
#ifdef XP_WIN32
else if (flagDbcsUri && s[
1] && IsDBCSLeadByte(s[
0]))
#else
else if (flagDbcsUri && s[
1] && (s[
0] & 0x80))
#endif
{
util_sprintf(d,
"%%%02x%%%02x", (
unsigned char)s[
0], (
unsigned char)s[
1]);
s +=
2; d +=
6;
}
else if (0x80 & *s) {
util_sprintf(d,
"%%%02x", (
unsigned char)*s);
++s; d +=
3;
}
else {
*d++ = *s++;
}
}
*d =
'\0';
return od;
}
NSAPI_PUBLIC char *util_url_escape(
char *od,
const char *s)
{
int flagDbcsUri = allow_dbcs_uri();
char *d;
if (!od)
od = (
char *)
MALLOC((strlen(s)*
3) +
1);
d = od;
while (*s) {
if (strchr(
"% +*\"''<>\r\n", *s)) {
util_sprintf(d,
"%%%02x", (
unsigned char)*s);
++s; d +=
3;
}
#ifdef XP_WIN32
else if (flagDbcsUri && s[
1] && IsDBCSLeadByte(s[
0]))
#else
else if (flagDbcsUri && s[
1] && (s[
0] & 0x80))
#endif
{
util_sprintf(d,
"%%%02x%%%02x", (
unsigned char)s[
0], (
unsigned char)s[
1]);
s +=
2; d +=
6;
}
else if (0x80 & *s) {
util_sprintf(d,
"%%%02x", (
unsigned char)*s);
++s; d +=
3;
}
else {
*d++ = *s++;
}
}
*d =
'\0';
return od;
}
NSAPI_PUBLIC char* util_uri_strip_params(
char *uri)
{
char* out;
if((out = strchr(uri,
';'))) {
char* in = out;
while (*in) {
if (*in ==
';') {
do in++;
while (*in && *in !=
'/');
}
else {
*out++ = *in++;
}
}
*out =
0;
}
return uri;
}
NSAPI_PUBLIC char* util_canonicalize_uri(
pool_handle_t *pool,
const char *uri,
int len,
int *pcanonlen)
{
PRBool success =
PR_TRUE;
const char *in_ptr = uri;
int in =
0;
int in_len = len;
char* canonPath = (
char *)pool_malloc(pool, in_len+
1);
char* out_ptr = canonPath;
if (!canonPath) {
success =
PR_FALSE;
goto done;
}
while (in < in_len) {
if (in_ptr[
0] !=
'/') {
*out_ptr++ = *in_ptr++;
in++;
continue;
}
if (in+
1 >= in_len) {
*out_ptr++ = *in_ptr++;
in++;
break;
}
switch(in_ptr[
1]) {
case '/':
in_ptr++;
in++;
break;
case '.':
if (in+
2 >= in_len) {
*out_ptr++ = *in_ptr++;
goto done;
}
if (in_ptr[
2] ==
'/') {
in_ptr +=
2;
in +=
2;
break;
}
if (in_ptr[
2] !=
'.') {
*out_ptr++ = *in_ptr++;
in++;
break;
}
if (in+
3 < in_len && in_ptr[
3] !=
'/' && in_ptr[
3] !=
';') {
*out_ptr++ = *in_ptr++;
in++;
}
else {
if (out_ptr == canonPath) {
success =
PR_FALSE;
goto done;
}
for (out_ptr--;
out_ptr != canonPath && out_ptr[
0] !=
'/';
out_ptr--);
if(in+
3 == in_len)
out_ptr++;
in_ptr +=
3;
in +=
3;
}
break;
default:
if (out_ptr == canonPath || *(out_ptr-
1) !=
'/')
*out_ptr++ = *in_ptr;
in_ptr++; in++;
break;
}
}
done:
if (success) {
unsigned canonLen = (
unsigned) (out_ptr - canonPath);
canonPath[canonLen] =
'\0';
if (pcanonlen) *pcanonlen = (
int) canonLen;
}
else {
pool_free(pool, canonPath);
canonPath =
NULL;
if (pcanonlen) *pcanonlen =
0;
}
return canonPath;
}
NSAPI_PUBLIC char* util_canonicalize_redirect(
pool_handle_t *pool,
const char *baseUri,
const char *newUri)
{
if (*newUri ==
'/')
return util_canonicalize_uri(pool, newUri, strlen(newUri),
NULL);
int bLen = strlen(baseUri);
if (bLen >
0 && baseUri[bLen -
1] !=
'/') {
while (bLen >
0 && baseUri[bLen -
1] !=
'/')
bLen--;
}
int pLen = strlen(newUri) + bLen +
1;
char *pUri = (
char *)pool_malloc(pool, pLen +
1);
if (!pUri)
return PR_FALSE;
memcpy(pUri, baseUri, bLen);
pUri[bLen] =
'/';
strcpy(pUri + bLen +
1, newUri);
char *rval = util_canonicalize_uri(pool, pUri, pLen,
NULL);
pool_free(pool, pUri);
return rval;
}
NSAPI_PUBLIC const char *util_host_port_suffix(
const char *h)
{
if (h ==
NULL)
return h;
for (;;) {
for (;;) {
char c = *h;
if (c ==
'\0')
return NULL;
if (c ==
'/')
return NULL;
if (c ==
':')
return h;
if (c ==
'[')
break;
h++;
}
while (*h !=
'\0' && *h !=
']')
h++;
}
}