1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23#include "curl_setup.h" 24 25#include "dotdot.h" 26 27#include "curl_memory.h" 28/* The last #include file should be: */ 29#include "memdebug.h" 30 31/* 32 * "Remove Dot Segments" 33 * http://tools.ietf.org/html/rfc3986#section-5.2.4 34 */ 35 36/* 37 * Curl_dedotdotify() 38 * 39 * This function gets a zero-terminated path with dot and dotdot sequences 40 * passed in and strips them off according to the rules in RFC 3986 section 41 * 5.2.4. 42 * 43 * The function handles a query part ('?' + stuff) appended but it expects 44 * that fragments ('#' + stuff) have already been cut off. 45 * 46 * RETURNS 47 * 48 * an allocated dedotdotified output string 49 */ 50char *Curl_dedotdotify(const char *input) 51{ 52 size_t inlen = strlen(input); 53 char *clone; 54 size_t clen = inlen; /* the length of the cloned input */ 55 char *out = malloc(inlen+1); 56 char *outptr; 57 char *orgclone; 58 char *queryp; 59 if(!out) 60 return NULL; /* out of memory */ 61 62 /* get a cloned copy of the input */ 63 clone = strdup(input); 64 if(!clone) { 65 free(out); 66 return NULL; 67 } 68 orgclone = clone; 69 outptr = out; 70 71 /* 72 * To handle query-parts properly, we must find it and remove it during the 73 * dotdot-operation and then append it again at the end to the output 74 * string. 75 */ 76 queryp = strchr(clone, '?'); 77 if(queryp) 78 *queryp = 0; 79 80 do { 81 82 /* A. If the input buffer begins with a prefix of "../" or "./", then 83 remove that prefix from the input buffer; otherwise, */ 84 85 if(!strncmp("./", clone, 2)) { 86 clone+=2; 87 clen-=2; 88 } 89 else if(!strncmp("../", clone, 3)) { 90 clone+=3; 91 clen-=3; 92 } 93 94 /* B. if the input buffer begins with a prefix of "/./" or "/.", where 95 "." is a complete path segment, then replace that prefix with "/" in 96 the input buffer; otherwise, */ 97 else if(!strncmp("/./", clone, 3)) { 98 clone+=2; 99 clen-=2; 100 } 101 else if(!strcmp("/.", clone)) { 102 clone[1]='/'; 103 clone++; 104 clen-=1; 105 } 106 107 /* C. if the input buffer begins with a prefix of "/../" or "/..", where 108 ".." is a complete path segment, then replace that prefix with "/" in 109 the input buffer and remove the last segment and its preceding "/" (if 110 any) from the output buffer; otherwise, */ 111 112 else if(!strncmp("/../", clone, 4)) { 113 clone+=3; 114 clen-=3; 115 /* remove the last segment from the output buffer */ 116 while(outptr > out) { 117 outptr--; 118 if(*outptr == '/') 119 break; 120 } 121 *outptr = 0; /* zero-terminate where it stops */ 122 } 123 else if(!strcmp("/..", clone)) { 124 clone[2]='/'; 125 clone+=2; 126 clen-=2; 127 /* remove the last segment from the output buffer */ 128 while(outptr > out) { 129 outptr--; 130 if(*outptr == '/') 131 break; 132 } 133 *outptr = 0; /* zero-terminate where it stops */ 134 } 135 136 /* D. if the input buffer consists only of "." or "..", then remove 137 that from the input buffer; otherwise, */ 138 139 else if(!strcmp(".", clone) || !strcmp("..", clone)) { 140 *clone=0; 141 } 142 143 else { 144 /* E. move the first path segment in the input buffer to the end of 145 the output buffer, including the initial "/" character (if any) and 146 any subsequent characters up to, but not including, the next "/" 147 character or the end of the input buffer. */ 148 149 do { 150 *outptr++ = *clone++; 151 clen--; 152 } while(*clone && (*clone != '/')); 153 *outptr = 0; 154 } 155 156 } while(*clone); 157 158 if(queryp) { 159 size_t qlen; 160 /* There was a query part, append that to the output. The 'clone' string 161 may now have been altered so we copy from the original input string 162 from the correct index. */ 163 size_t oindex = queryp - orgclone; 164 qlen = strlen(&input[oindex]); 165 memcpy(outptr, &input[oindex], qlen+1); /* include the ending zero byte */ 166 } 167 168 free(orgclone); 169 return out; 170} 171