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 *copyFrom = in;
|
||||
char *max = in + size;
|
||||
char **Segments = NULL;
|
||||
int lastSegment = -1;
|
||||
char *in = buf;
|
||||
char *out = buf;
|
||||
char *max = buf + size;
|
||||
|
||||
Segments = malloc( sizeof( char * ) * size );
|
||||
while (!is_end_path(in[0])) {
|
||||
assert (buf <= out);
|
||||
assert (out <= in);
|
||||
assert (in < max);
|
||||
|
||||
if( Segments == NULL )
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
|
||||
Segments[0] = NULL;
|
||||
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
||||
"REMOVE_DOTS: before: %s\n", in );
|
||||
while( ( copyFrom < max ) && ( *copyFrom != '?' )
|
||||
&& ( *copyFrom != '#' ) ) {
|
||||
|
||||
if( ( ( *copyFrom ) == '.' )
|
||||
&& ( ( copyFrom == in ) || ( *( copyFrom - 1 ) == '/' ) ) ) {
|
||||
if( ( copyFrom + 1 == max )
|
||||
|| ( *( copyFrom + 1 ) == '/' ) ) {
|
||||
|
||||
copyFrom += 2;
|
||||
continue;
|
||||
} else if( ( *( copyFrom + 1 ) == '.' )
|
||||
&& ( ( copyFrom + 2 == max )
|
||||
|| ( *( copyFrom + 2 ) == '/' ) ) ) {
|
||||
copyFrom += 3;
|
||||
|
||||
if( lastSegment > 0 ) {
|
||||
copyTo = Segments[--lastSegment];
|
||||
} else {
|
||||
free( Segments );
|
||||
/*TRACE("ERROR RESOLVING URL, ../ at ROOT"); */
|
||||
return UPNP_E_INVALID_URL;
|
||||
}
|
||||
continue;
|
||||
/* case 2.A: */
|
||||
if (strncmp(in, "./", 2) == 0) {
|
||||
in += 2;
|
||||
} else if (strncmp(in, "../", 3) == 0) {
|
||||
in += 3;
|
||||
/* case 2.B: */
|
||||
} else if (strncmp(in, "/./", 3) == 0) {
|
||||
in += 2;
|
||||
} else if (strncmp(in, "/.", 2) == 0 && is_end_path(in[2])) {
|
||||
in += 1;
|
||||
in[0] = '/';
|
||||
/* case 2.C: */
|
||||
} else if (strncmp(in, "/../", 4) == 0 || (strncmp(in, "/..", 3) == 0 && is_end_path(in[3]))) {
|
||||
/* Make the next character in the input buffer a '/': */
|
||||
if (is_end_path(in[3])) { /* terminating "/.." case */
|
||||
in += 2;
|
||||
in[0] = '/';
|
||||
} else { /* "/../" prefix case */
|
||||
in += 3;
|
||||
}
|
||||
}
|
||||
|
||||
if( ( *copyFrom ) == '/' ) {
|
||||
|
||||
lastSegment++;
|
||||
Segments[lastSegment] = copyTo + 1;
|
||||
}
|
||||
( *copyTo ) = ( *copyFrom );
|
||||
copyTo++;
|
||||
copyFrom++;
|
||||
}
|
||||
if( copyFrom < max ) {
|
||||
while( copyFrom < max ) {
|
||||
( *copyTo ) = ( *copyFrom );
|
||||
copyTo++;
|
||||
copyFrom++;
|
||||
/* Trim the last component from the output buffer, or empty it. */
|
||||
while (buf < out)
|
||||
if (*--out == '/')
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
if (out < in)
|
||||
out[0] = '\0';
|
||||
#endif
|
||||
/* case 2.D: */
|
||||
} else if (strncmp(in, ".", 1) == 0 && is_end_path(in[1])) {
|
||||
in += 1;
|
||||
} else if (strncmp(in, "..", 2) == 0 && is_end_path(in[2])) {
|
||||
in += 2;
|
||||
/* case 2.E */
|
||||
} else {
|
||||
/* 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;
|
||||
free( Segments );
|
||||
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
||||
"REMOVE_DOTS: after: %s\n", in );
|
||||
while (in < max)
|
||||
*out++ = *in++;
|
||||
if (out < max)
|
||||
out[0] = '\0';
|
||||
return UPNP_E_SUCCESS;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user