Fix remove_dots()
Rewrite to handle all normal and abnormal examples mentioned in RFC 3986 section 5.4. The previous implementation failed the following test cases: 'http://www.libupnp.org/path1/path1' | '#frag1' -> 'http://www.libupnp.org/path1/#frag1' != 'http://www.libupnp.org/path1/path1#frag1' (0) 'http://127.0.0.1:6544/getDeviceDesc' | 'CDS_Event' -> 'http://127.0.0.1:6544/CDS_EventDesc' != 'http://127.0.0.1:6544/CDS_Event' (0) 'http://localhost/b/c/d;p?q' | 'g' -> 'http://localhost/b/c/g;p' != 'http://localhost/b/c/g' (0) 'http://localhost/b/c/d;p?q' | 'g/' -> 'http://localhost/b/c/g/p' != 'http://localhost/b/c/g/' (0) 'http://localhost/b/c/d;p?q' | '?y' -> 'http://localhost/b/c/?yp' != 'http://localhost/b/c/d;p?y' (0) 'http://localhost/b/c/d;p?q' | '#s' -> 'http://localhost/b/c/#sp' != 'http://localhost/b/c/d;p?q#s' (0) 'http://localhost/b/c/d;p?q' | ';x' -> 'http://localhost/b/c/;xp' != 'http://localhost/b/c/;x' (0) 'http://localhost/b/c/d;p?q' | '.' -> 'http://localhost/b/c/.;p' != 'http://localhost/b/c/' (0) 'http://localhost/b/c/d;p?q' | './' -> 'http://localhost/b/c/p' != 'http://localhost/b/c/' (0) 'http://localhost/b/c/d;p?q' | '..' -> 'http://localhost/b/c/..p' != 'http://localhost/b/' (0) 'http://localhost/b/c/d;p?q' | '/./g' -> 'http://localhost/./g' != 'http://localhost/g' (0) 'http://localhost/b/c/d;p?q' | '/../g' -> 'http://localhost/../g' != 'http://localhost/g' (0) 'http://localhost/b/c/d;p?q' | 'g.' -> 'http://localhost/b/c/g.p' != 'http://localhost/b/c/g.' (0) 'http://localhost/b/c/d;p?q' | '.g' -> 'http://localhost/b/c/.gp' != 'http://localhost/b/c/.g' (0) Signed-off-by: Marcelo Roberto Jimenez <mroberto@users.sourceforge.net>
This commit is contained in:
parent
0508fb0d6e
commit
fbbb24f406
@ -510,68 +510,81 @@ int remove_escaped_chars(INOUT char *in, INOUT size_t *size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int remove_dots(char *in, size_t size)
|
static UPNP_INLINE int is_end_path(char c) {
|
||||||
|
switch (c) {
|
||||||
|
case '?':
|
||||||
|
case '#':
|
||||||
|
case '\0':
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function directly implements the "Remove Dot Segments"
|
||||||
|
* algorithm described in RFC 3986 section 5.2.4. */
|
||||||
|
int remove_dots(char *buf, size_t size)
|
||||||
{
|
{
|
||||||
char *copyTo = in;
|
char *in = buf;
|
||||||
char *copyFrom = in;
|
char *out = buf;
|
||||||
char *max = in + size;
|
char *max = buf + size;
|
||||||
char **Segments = NULL;
|
|
||||||
int lastSegment = -1;
|
|
||||||
|
|
||||||
Segments = malloc( sizeof( char * ) * size );
|
while (!is_end_path(in[0])) {
|
||||||
|
assert (buf <= out);
|
||||||
|
assert (out <= in);
|
||||||
|
assert (in < max);
|
||||||
|
|
||||||
if( Segments == NULL )
|
/* case 2.A: */
|
||||||
return UPNP_E_OUTOF_MEMORY;
|
if (strncmp(in, "./", 2) == 0) {
|
||||||
|
in += 2;
|
||||||
Segments[0] = NULL;
|
} else if (strncmp(in, "../", 3) == 0) {
|
||||||
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
in += 3;
|
||||||
"REMOVE_DOTS: before: %s\n", in );
|
/* case 2.B: */
|
||||||
while( ( copyFrom < max ) && ( *copyFrom != '?' )
|
} else if (strncmp(in, "/./", 3) == 0) {
|
||||||
&& ( *copyFrom != '#' ) ) {
|
in += 2;
|
||||||
|
} else if (strncmp(in, "/.", 2) == 0 && is_end_path(in[2])) {
|
||||||
if( ( ( *copyFrom ) == '.' )
|
in += 1;
|
||||||
&& ( ( copyFrom == in ) || ( *( copyFrom - 1 ) == '/' ) ) ) {
|
in[0] = '/';
|
||||||
if( ( copyFrom + 1 == max )
|
/* case 2.C: */
|
||||||
|| ( *( copyFrom + 1 ) == '/' ) ) {
|
} else if (strncmp(in, "/../", 4) == 0 || (strncmp(in, "/..", 3) == 0 && is_end_path(in[3]))) {
|
||||||
|
/* Make the next character in the input buffer a '/': */
|
||||||
copyFrom += 2;
|
if (is_end_path(in[3])) { /* terminating "/.." case */
|
||||||
continue;
|
in += 2;
|
||||||
} else if( ( *( copyFrom + 1 ) == '.' )
|
in[0] = '/';
|
||||||
&& ( ( copyFrom + 2 == max )
|
} else { /* "/../" prefix case */
|
||||||
|| ( *( copyFrom + 2 ) == '/' ) ) ) {
|
in += 3;
|
||||||
copyFrom += 3;
|
|
||||||
|
|
||||||
if( lastSegment > 0 ) {
|
|
||||||
copyTo = Segments[--lastSegment];
|
|
||||||
} else {
|
|
||||||
free( Segments );
|
|
||||||
/*TRACE("ERROR RESOLVING URL, ../ at ROOT"); */
|
|
||||||
return UPNP_E_INVALID_URL;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
/* Trim the last component from the output buffer, or empty it. */
|
||||||
|
while (buf < out)
|
||||||
if( ( *copyFrom ) == '/' ) {
|
if (*--out == '/')
|
||||||
|
break;
|
||||||
lastSegment++;
|
#ifdef DEBUG
|
||||||
Segments[lastSegment] = copyTo + 1;
|
if (out < in)
|
||||||
}
|
out[0] = '\0';
|
||||||
( *copyTo ) = ( *copyFrom );
|
#endif
|
||||||
copyTo++;
|
/* case 2.D: */
|
||||||
copyFrom++;
|
} else if (strncmp(in, ".", 1) == 0 && is_end_path(in[1])) {
|
||||||
}
|
in += 1;
|
||||||
if( copyFrom < max ) {
|
} else if (strncmp(in, "..", 2) == 0 && is_end_path(in[2])) {
|
||||||
while( copyFrom < max ) {
|
in += 2;
|
||||||
( *copyTo ) = ( *copyFrom );
|
/* case 2.E */
|
||||||
copyTo++;
|
} else {
|
||||||
copyFrom++;
|
/* move initial '/' character (if any) */
|
||||||
|
if (in[0] == '/')
|
||||||
|
*out++ = *in++;
|
||||||
|
/* move first segment up to, but not including, the next '/' character */
|
||||||
|
while (in < max && in[0] != '/' && !is_end_path(in[0]))
|
||||||
|
*out++ = *in++;
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (out < in)
|
||||||
|
out[0] = '\0';
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
( *copyTo ) = 0;
|
while (in < max)
|
||||||
free( Segments );
|
*out++ = *in++;
|
||||||
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
if (out < max)
|
||||||
"REMOVE_DOTS: after: %s\n", in );
|
out[0] = '\0';
|
||||||
return UPNP_E_SUCCESS;
|
return UPNP_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user