@@ -206,83 +206,96 @@ void gitno_connection_data_free_ptrs(gitno_connection_data *d)
206206 git__free (d -> pass ); d -> pass = NULL ;
207207}
208208
209- #define hex2c (c ) ((c | 32) % 39 - 9)
210- static char * unescape (char * str )
211- {
212- int x , y ;
213- int len = (int )strlen (str );
214-
215- for (x = y = 0 ; str [y ]; ++ x , ++ y ) {
216- if ((str [x ] = str [y ]) == '%' ) {
217- if (y < len - 2 && isxdigit (str [y + 1 ]) && isxdigit (str [y + 2 ])) {
218- str [x ] = (hex2c (str [y + 1 ]) << 4 ) + hex2c (str [y + 2 ]);
219- y += 2 ;
220- }
221- }
222- }
223- str [x ] = '\0' ;
224- return str ;
225- }
226-
227209int gitno_extract_url_parts (
228- char * * host ,
229- char * * port ,
230- char * * path ,
231- char * * username ,
232- char * * password ,
233- const char * url ,
234- const char * default_port )
210+ char * * host_out ,
211+ char * * port_out ,
212+ char * * path_out ,
213+ char * * username_out ,
214+ char * * password_out ,
215+ const char * url ,
216+ const char * default_port )
235217{
236218 struct http_parser_url u = {0 };
237- const char * _host , * _port , * _path , * _userinfo ;
219+ bool has_host , has_port , has_path , has_userinfo ;
220+ git_buf host = GIT_BUF_INIT ,
221+ port = GIT_BUF_INIT ,
222+ path = GIT_BUF_INIT ,
223+ username = GIT_BUF_INIT ,
224+ password = GIT_BUF_INIT ;
225+ int error = 0 ;
238226
239227 if (http_parser_parse_url (url , strlen (url ), false, & u )) {
240228 giterr_set (GITERR_NET , "malformed URL '%s'" , url );
241- return GIT_EINVALIDSPEC ;
229+ error = GIT_EINVALIDSPEC ;
230+ goto done ;
242231 }
243232
244- _host = url + u . field_data [ UF_HOST ]. off ;
245- _port = url + u . field_data [ UF_PORT ]. off ;
246- _path = url + u . field_data [ UF_PATH ]. off ;
247- _userinfo = url + u . field_data [ UF_USERINFO ]. off ;
233+ has_host = !!( u . field_set & ( 1 << UF_HOST )) ;
234+ has_port = !!( u . field_set & ( 1 << UF_PORT )) ;
235+ has_path = !!( u . field_set & ( 1 << UF_PATH )) ;
236+ has_userinfo = !!( u . field_set & ( 1 << UF_USERINFO )) ;
248237
249- if (u .field_set & (1 << UF_HOST )) {
250- * host = git__substrdup (_host , u .field_data [UF_HOST ].len );
251- GITERR_CHECK_ALLOC (* host );
238+ if (has_host ) {
239+ const char * url_host = url + u .field_data [UF_HOST ].off ;
240+ size_t url_host_len = u .field_data [UF_HOST ].len ;
241+ git_buf_decode_percent (& host , url_host , url_host_len );
252242 }
253243
254- if (u .field_set & (1 << UF_PORT ))
255- * port = git__substrdup (_port , u .field_data [UF_PORT ].len );
256- else
257- * port = git__strdup (default_port );
258- GITERR_CHECK_ALLOC (* port );
244+ if (has_port ) {
245+ const char * url_port = url + u .field_data [UF_PORT ].off ;
246+ size_t url_port_len = u .field_data [UF_PORT ].len ;
247+ git_buf_put (& port , url_port , url_port_len );
248+ } else {
249+ git_buf_puts (& port , default_port );
250+ }
259251
260- if (path ) {
261- if (u .field_set & (1 << UF_PATH )) {
262- * path = git__substrdup (_path , u .field_data [UF_PATH ].len );
263- GITERR_CHECK_ALLOC (* path );
264- } else {
265- git__free (* port );
266- * port = NULL ;
267- git__free (* host );
268- * host = NULL ;
269- giterr_set (GITERR_NET , "invalid url, missing path" );
270- return GIT_EINVALIDSPEC ;
271- }
252+ if (has_path && path_out ) {
253+ const char * url_path = url + u .field_data [UF_PATH ].off ;
254+ size_t url_path_len = u .field_data [UF_PATH ].len ;
255+ git_buf_decode_percent (& path , url_path , url_path_len );
256+ } else if (path_out ) {
257+ giterr_set (GITERR_NET , "invalid url, missing path" );
258+ error = GIT_EINVALIDSPEC ;
259+ goto done ;
272260 }
273261
274- if (u .field_set & (1 << UF_USERINFO )) {
275- const char * colon = memchr (_userinfo , ':' , u .field_data [UF_USERINFO ].len );
262+ if (has_userinfo ) {
263+ const char * url_userinfo = url + u .field_data [UF_USERINFO ].off ;
264+ size_t url_userinfo_len = u .field_data [UF_USERINFO ].len ;
265+ const char * colon = memchr (url_userinfo , ':' , url_userinfo_len );
266+
276267 if (colon ) {
277- * username = unescape (git__substrdup (_userinfo , colon - _userinfo ));
278- * password = unescape (git__substrdup (colon + 1 , u .field_data [UF_USERINFO ].len - (colon + 1 - _userinfo )));
279- GITERR_CHECK_ALLOC (* password );
268+ const char * url_username = url_userinfo ;
269+ size_t url_username_len = colon - url_userinfo ;
270+ const char * url_password = colon + 1 ;
271+ size_t url_password_len = url_userinfo_len - (url_username_len + 1 );
272+
273+ git_buf_decode_percent (& username , url_username , url_username_len );
274+ git_buf_decode_percent (& password , url_password , url_password_len );
280275 } else {
281- * username = git__substrdup ( _userinfo , u . field_data [ UF_USERINFO ]. len );
276+ git_buf_decode_percent ( & username , url_userinfo , url_userinfo_len );
282277 }
283- GITERR_CHECK_ALLOC (* username );
284-
285278 }
286279
287- return 0 ;
280+ if (git_buf_oom (& host ) ||
281+ git_buf_oom (& port ) ||
282+ git_buf_oom (& path ) ||
283+ git_buf_oom (& username ) ||
284+ git_buf_oom (& password ))
285+ return -1 ;
286+
287+ * host_out = git_buf_detach (& host );
288+ * port_out = git_buf_detach (& port );
289+ if (path_out )
290+ * path_out = git_buf_detach (& path );
291+ * username_out = git_buf_detach (& username );
292+ * password_out = git_buf_detach (& password );
293+
294+ done :
295+ git_buf_free (& host );
296+ git_buf_free (& port );
297+ git_buf_free (& path );
298+ git_buf_free (& username );
299+ git_buf_free (& password );
300+ return error ;
288301}
0 commit comments