@@ -225,64 +225,95 @@ char* gitno_unescape(char *str)
225225}
226226
227227int 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 )
228+ char * * host_out ,
229+ char * * port_out ,
230+ char * * path_out ,
231+ char * * username_out ,
232+ char * * password_out ,
233+ const char * url ,
234+ const char * default_port )
235235{
236236 struct http_parser_url u = {0 };
237- const char * _host , * _port , * _path , * _userinfo ;
237+ bool has_host , has_port , has_path , has_userinfo ;
238+ git_buf host = GIT_BUF_INIT ,
239+ port = GIT_BUF_INIT ,
240+ path = GIT_BUF_INIT ,
241+ username = GIT_BUF_INIT ,
242+ password = GIT_BUF_INIT ;
243+ int error = 0 ;
238244
239245 if (http_parser_parse_url (url , strlen (url ), false, & u )) {
240246 giterr_set (GITERR_NET , "malformed URL '%s'" , url );
241- return GIT_EINVALIDSPEC ;
247+ error = GIT_EINVALIDSPEC ;
248+ goto done ;
242249 }
243250
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 ;
251+ has_host = !!( u . field_set & ( 1 << UF_HOST )) ;
252+ has_port = !!( u . field_set & ( 1 << UF_PORT )) ;
253+ has_path = !!( u . field_set & ( 1 << UF_PATH )) ;
254+ has_userinfo = !!( u . field_set & ( 1 << UF_USERINFO )) ;
248255
249- if (u .field_set & (1 << UF_HOST )) {
250- * host = git__substrdup (_host , u .field_data [UF_HOST ].len );
251- GITERR_CHECK_ALLOC (* host );
256+ if (has_host ) {
257+ const char * url_host = url + u .field_data [UF_HOST ].off ;
258+ size_t url_host_len = u .field_data [UF_HOST ].len ;
259+ git_buf_put (& host , url_host , url_host_len );
252260 }
253261
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 );
262+ if (has_port ) {
263+ const char * url_port = url + u .field_data [UF_PORT ].off ;
264+ size_t url_port_len = u .field_data [UF_PORT ].len ;
265+ git_buf_put (& port , url_port , url_port_len );
266+ } else {
267+ git_buf_puts (& port , default_port );
268+ }
259269
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- }
270+ if (has_path && path_out ) {
271+ const char * url_path = url + u .field_data [UF_PATH ].off ;
272+ size_t url_path_len = u .field_data [UF_PATH ].len ;
273+ git_buf_decode_percent (& path , url_path , url_path_len );
274+ } else if (path_out ) {
275+ giterr_set (GITERR_NET , "invalid url, missing path" );
276+ error = GIT_EINVALIDSPEC ;
277+ goto done ;
272278 }
273279
274- if (u .field_set & (1 << UF_USERINFO )) {
275- const char * colon = memchr (_userinfo , ':' , u .field_data [UF_USERINFO ].len );
280+ if (has_userinfo ) {
281+ const char * url_userinfo = url + u .field_data [UF_USERINFO ].off ;
282+ size_t url_userinfo_len = u .field_data [UF_USERINFO ].len ;
283+ const char * colon = memchr (url_userinfo , ':' , url_userinfo_len );
284+
276285 if (colon ) {
277- * username = gitno_unescape (git__substrdup (_userinfo , colon - _userinfo ));
278- * password = gitno_unescape (git__substrdup (colon + 1 , u .field_data [UF_USERINFO ].len - (colon + 1 - _userinfo )));
279- GITERR_CHECK_ALLOC (* password );
286+ const char * url_username = url_userinfo ;
287+ size_t url_username_len = colon - url_userinfo ;
288+ const char * url_password = colon + 1 ;
289+ size_t url_password_len = url_userinfo_len - (url_username_len + 1 );
290+
291+ git_buf_decode_percent (& username , url_username , url_username_len );
292+ git_buf_decode_percent (& password , url_password , url_password_len );
280293 } else {
281- * username = git__substrdup ( _userinfo , u . field_data [ UF_USERINFO ]. len );
294+ git_buf_decode_percent ( & username , url_userinfo , url_userinfo_len );
282295 }
283- GITERR_CHECK_ALLOC (* username );
284-
285296 }
286297
287- return 0 ;
298+ if (git_buf_oom (& host ) ||
299+ git_buf_oom (& port ) ||
300+ git_buf_oom (& path ) ||
301+ git_buf_oom (& username ) ||
302+ git_buf_oom (& password ))
303+ return -1 ;
304+
305+ * host_out = git_buf_detach (& host );
306+ * port_out = git_buf_detach (& port );
307+ if (path_out )
308+ * path_out = git_buf_detach (& path );
309+ * username_out = git_buf_detach (& username );
310+ * password_out = git_buf_detach (& password );
311+
312+ done :
313+ git_buf_free (& host );
314+ git_buf_free (& port );
315+ git_buf_free (& path );
316+ git_buf_free (& username );
317+ git_buf_free (& password );
318+ return error ;
288319}
0 commit comments