@@ -780,6 +780,44 @@ static int is_file(const char *url)
780780 return S_ISREG (buf .st_mode );
781781}
782782
783+ static int is_url (const char * url )
784+ {
785+ const char * url2 , * first_slash ;
786+
787+ if (!url )
788+ return 0 ;
789+ url2 = url ;
790+ first_slash = strchr (url , '/' );
791+
792+ /* Input with no slash at all or slash first can't be URL. */
793+ if (!first_slash || first_slash == url )
794+ return 0 ;
795+ /* Character before must be : and next must be /. */
796+ if (first_slash [-1 ] != ':' || first_slash [1 ] != '/' )
797+ return 0 ;
798+ /* There must be something before the :// */
799+ if (first_slash == url + 1 )
800+ return 0 ;
801+ /*
802+ * Check all characters up to first slash - 1. Only alphanum
803+ * is allowed.
804+ */
805+ url2 = url ;
806+ while (url2 < first_slash - 1 ) {
807+ if (!isalnum ((unsigned char )* url2 ))
808+ return 0 ;
809+ url2 ++ ;
810+ }
811+
812+ /* Valid enough. */
813+ return 1 ;
814+ }
815+
816+ static int external_specification_len (const char * url )
817+ {
818+ return strchr (url , ':' ) - url ;
819+ }
820+
783821struct transport * transport_get (struct remote * remote , const char * url )
784822{
785823 struct transport * ret = xcalloc (1 , sizeof (* ret ));
@@ -805,30 +843,23 @@ struct transport *transport_get(struct remote *remote, const char *url)
805843
806844 if (remote && remote -> foreign_vcs ) {
807845 transport_helper_init (ret , remote -> foreign_vcs );
808- return ret ;
809- }
810-
811- if (!prefixcmp (url , "rsync:" )) {
846+ } else if (!prefixcmp (url , "rsync:" )) {
812847 ret -> get_refs_list = get_refs_via_rsync ;
813848 ret -> fetch = fetch_objs_via_rsync ;
814849 ret -> push = rsync_transport_push ;
815-
816- } else if (!prefixcmp (url , "http://" )
817- || !prefixcmp (url , "https://" )
818- || !prefixcmp (url , "ftp://" )) {
819- transport_helper_init (ret , "curl" );
820- #ifdef NO_CURL
821- error ("git was compiled without libcurl support." );
822- #endif
823-
824850 } else if (is_local (url ) && is_file (url )) {
825851 struct bundle_transport_data * data = xcalloc (1 , sizeof (* data ));
826852 ret -> data = data ;
827853 ret -> get_refs_list = get_refs_from_bundle ;
828854 ret -> fetch = fetch_refs_from_bundle ;
829855 ret -> disconnect = close_bundle ;
830-
831- } else {
856+ } else if (!is_url (url )
857+ || !prefixcmp (url , "file://" )
858+ || !prefixcmp (url , "git://" )
859+ || !prefixcmp (url , "ssh://" )
860+ || !prefixcmp (url , "git+ssh://" )
861+ || !prefixcmp (url , "ssh+git://" )) {
862+ /* These are builtin smart transports. */
832863 struct git_transport_data * data = xcalloc (1 , sizeof (* data ));
833864 ret -> data = data ;
834865 ret -> set_option = set_git_option ;
@@ -845,6 +876,21 @@ struct transport *transport_get(struct remote *remote, const char *url)
845876 data -> receivepack = "git-receive-pack" ;
846877 if (remote -> receivepack )
847878 data -> receivepack = remote -> receivepack ;
879+ } else if (!prefixcmp (url , "http://" )
880+ || !prefixcmp (url , "https://" )
881+ || !prefixcmp (url , "ftp://" )) {
882+ /* These three are just plain special. */
883+ transport_helper_init (ret , "curl" );
884+ #ifdef NO_CURL
885+ error ("git was compiled without libcurl support." );
886+ #endif
887+ } else {
888+ /* Unknown protocol in URL. Pass to external handler. */
889+ int len = external_specification_len (url );
890+ char * handler = xmalloc (len + 1 );
891+ handler [len ] = 0 ;
892+ strncpy (handler , url , len );
893+ transport_helper_init (ret , handler );
848894 }
849895
850896 return ret ;
0 commit comments