@@ -25,6 +25,7 @@ extern "C" {
2525#endif /* defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \
2626 defined(__NT__) */
2727#include <acquire_common_defs.h>
28+ #include <stdlib.h>
2829#include <string.h>
2930#ifndef NAME_MAX
3031#define NAME_MAX 4096
@@ -34,14 +35,13 @@ extern "C" {
3435 * @brief Extract the path component (filename) from a URL string.
3536 *
3637 * Given a URL string, returns a newly allocated string containing
37- * everything after the last '/' character in the URL, stopping before any
38- * query ('?') or fragment ('#') delimiter.
39- *
40- * If the URL is NULL or empty, returns NULL.
38+ * everything after the last '/' character in the URL's path, stopping before
39+ * any query ('?') or fragment ('#') delimiter.
4140 *
4241 * @param url Input URL string.
43- * @return Pointer to a newly allocated string, or `NULL` on failure.
44- * The caller is responsible for freeing this memory.
42+ * @return Pointer to a newly allocated string, or `NULL` on failure or if the
43+ * input is NULL/empty. The caller is responsible for freeing this
44+ * memory.
4545 */
4646extern LIBACQUIRE_EXPORT char * get_path_from_url (const char * url );
4747
@@ -62,44 +62,52 @@ extern LIBACQUIRE_EXPORT bool is_url(const char *maybe_url);
6262#include <acquire_string_extras.h>
6363
6464char * get_path_from_url (const char * url ) {
65- char buf [NAME_MAX + 1 ];
66- const char * last_slash , * end ;
65+ const char * path_start , * filename_start , * query_or_frag ;
6766 size_t len ;
67+ char * result ;
6868
69- if (!url || url [ 0 ] == '\0' )
69+ if (!url || ! * url ) {
7070 return NULL ;
71+ }
7172
72- last_slash = strrchr (url , '/' );
73- if (last_slash ) {
74- if ((last_slash - url ) < 9 )
73+ path_start = strstr (url , "://" );
74+ if (path_start ) {
75+ /* It's a URL. Find the path part, which starts after the authority. */
76+ path_start = strchr (path_start + 3 , '/' );
77+ if (!path_start ) {
78+ /* URL has host, but no path. E.g. http://example.com */
7579 return strdup ("" );
76- last_slash ++ ;
77- } else
78- last_slash = url ;
79-
80- end = last_slash ;
81- while (* end != '\0' && * end != '?' && * end != '#' ) {
82- end ++ ;
80+ }
81+ } else {
82+ /* Not a full URL with scheme. Treat as local path. */
83+ path_start = url ;
8384 }
8485
85- len = end - last_slash ;
86- if (len >= sizeof (buf )) {
87- len = sizeof (buf ) - 1 ;
86+ /* Now path_start points to the beginning of the path, e.g.,
87+ * "/path/to/file.txt" */
88+ filename_start = strrchr (path_start , '/' );
89+ if (filename_start ) {
90+ /* We found a slash, the filename is after it */
91+ filename_start ++ ;
92+ } else {
93+ /* No slashes in path, the whole path is the filename */
94+ filename_start = path_start ;
8895 }
8996
90- #if defined(_MSC_VER ) && !defined(__INTEL_COMPILER ) || \
91- defined(__STDC_LIB_EXT1__ ) && __STDC_WANT_LIB_EXT1__
92- {
93- const errno_t e = strncpy_s (buf , sizeof buf , url , NAME_MAX + 1 );
94- if (e )
95- buf [0 ] = '\0' ;
97+ /* Find end of filename (start of query or fragment) */
98+ query_or_frag = filename_start ;
99+ while (* query_or_frag && * query_or_frag != '?' && * query_or_frag != '#' ) {
100+ query_or_frag ++ ;
96101 }
97- #else
98- strncpy (buf , last_slash , len );
99- #endif
100- buf [len ] = '\0' ;
101102
102- return strdup (buf );
103+ len = query_or_frag - filename_start ;
104+ result = (char * )malloc (len + 1 );
105+ if (!result )
106+ return NULL ; /* LCOV_EXCL_LINE */
107+
108+ memcpy (result , filename_start , len );
109+ result [len ] = '\0' ;
110+ return result ;
103111}
104112
105113bool is_url (const char * maybe_url ) {
0 commit comments