Changeset 14639


Ignore:
Timestamp:
Dec 28, 2015, 11:52:26 PM (7 years ago)
Author:
mikedld
Message:

Optimize URL-parsing functions a bit; rewrite tr_urlParse()

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/gtk/tr-prefs.c

    r14633 r14639  
    502502{
    503503  gchar * url = gtk_editable_get_chars (e, 0, -1);
    504   const gboolean err = tr_urlParse (url, TR_BAD_SIZE, NULL, NULL, NULL, NULL);
    505   gtk_widget_set_sensitive (GTK_WIDGET (gbutton), !err);
     504  const gboolean is_url_valid = tr_urlParse (url, TR_BAD_SIZE, NULL, NULL, NULL, NULL);
     505  gtk_widget_set_sensitive (GTK_WIDGET (gbutton), is_url_valid);
    506506  g_free (url);
    507507}
  • trunk/libtransmission/utils-test.c

    r14633 r14639  
    318318
    319319  url = "http://1";
    320   check (!tr_urlParse (url, TR_BAD_SIZE, &scheme, &host, &port, &path));
     320  check (tr_urlParse (url, TR_BAD_SIZE, &scheme, &host, &port, &path));
    321321  check_streq ("http", scheme);
    322322  check_streq ("1", host);
     
    328328
    329329  url = "http://www.some-tracker.org/some/path";
    330   check (!tr_urlParse (url, TR_BAD_SIZE, &scheme, &host, &port, &path));
     330  check (tr_urlParse (url, TR_BAD_SIZE, &scheme, &host, &port, &path));
    331331  check_streq ("http", scheme);
    332332  check_streq ("www.some-tracker.org", host);
     
    338338
    339339  url = "http://www.some-tracker.org:80/some/path";
    340   check (!tr_urlParse (url, TR_BAD_SIZE, &scheme, &host, &port, &path));
     340  check (tr_urlParse (url, TR_BAD_SIZE, &scheme, &host, &port, &path));
    341341  check_streq ("http", scheme);
    342342  check_streq ("www.some-tracker.org", host);
  • trunk/libtransmission/utils.c

    r14633 r14639  
    674674isValidURLChars (const char * url, size_t url_len)
    675675{
    676   const char * c;
    677   const char * end;
    678   static const char * rfc2396_valid_chars =
     676  static const char rfc2396_valid_chars[] =
    679677    "abcdefghijklmnopqrstuvwxyz" /* lowalpha */
    680678    "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* upalpha */
     
    688686    return false;
    689687
    690   for (c=url, end=c+url_len; c && *c && c!=end; ++c)
    691     if (!strchr (rfc2396_valid_chars, *c))
     688  for (const char * c = url, * end = url + url_len; c < end && *c != '\0'; ++c)
     689    if (memchr (rfc2396_valid_chars, *c, sizeof (rfc2396_valid_chars) - 1) == NULL)
    692690      return false;
    693691
     
    695693}
    696694
    697 /** @brief return true if the URL is a http or https or UDP one that Transmission understands */
    698695bool
    699696tr_urlIsValidTracker (const char * url)
    700697{
    701   bool valid;
    702 
    703698  if (url == NULL)
    704     {
    705       valid = false;
    706     }
    707   else
    708     {
    709       const size_t len = strlen (url);
    710 
    711       valid = isValidURLChars (url, len)
    712            && !tr_urlParse (url, len, NULL, NULL, NULL, NULL)
    713            && (!memcmp (url,"http://",7) || !memcmp (url,"https://",8) || !memcmp (url,"udp://",6));
    714     }
    715 
    716   return valid;
    717 }
    718 
    719 /** @brief return true if the URL is a http or https or ftp or sftp one that Transmission understands */
     699    return false;
     700
     701  const size_t url_len = strlen (url);
     702
     703  return isValidURLChars (url, url_len)
     704      && tr_urlParse (url, url_len, NULL, NULL, NULL, NULL)
     705      && (memcmp (url, "http://", 7) == 0 || memcmp (url, "https://", 8) == 0 ||
     706          memcmp (url, "udp://", 6) == 0);
     707}
     708
    720709bool
    721 tr_urlIsValid (const char * url, size_t url_len)
    722 {
    723   bool valid;
    724 
     710tr_urlIsValid (const char * url,
     711               size_t       url_len)
     712{
    725713  if (url == NULL)
    726     {
    727       valid = false;
    728     }
    729   else
    730     {
    731       if (url_len == TR_BAD_SIZE)
    732         url_len = strlen (url);
    733 
    734       valid = isValidURLChars (url, url_len)
    735            && !tr_urlParse (url, url_len, NULL, NULL, NULL, NULL)
    736            && (!memcmp (url,"http://",7) || !memcmp (url,"https://",8) || !memcmp (url,"ftp://",6) || !memcmp (url,"sftp://",7));
    737     }
    738 
    739   return valid;
     714    return false;
     715
     716  if (url_len == TR_BAD_SIZE)
     717    url_len = strlen (url);
     718
     719  return isValidURLChars (url, url_len)
     720      && tr_urlParse (url, url_len, NULL, NULL, NULL, NULL)
     721      && (memcmp (url, "http://", 7) == 0 || memcmp (url, "https://", 8) == 0 ||
     722          memcmp (url, "ftp://", 6) == 0 || memcmp (url, "sftp://", 7) == 0);
    740723}
    741724
     
    747730}
    748731
    749 int
    750 tr_urlParse (const char * url_in,
    751              size_t       len,
    752              char **      setme_protocol,
    753              char **      setme_host,
    754              int *        setme_port,
    755              char **      setme_path)
    756 {
    757   int err;
    758   int port = 0;
    759   size_t n;
    760   char * tmp;
    761   char * pch;
    762   size_t host_len;
    763   size_t protocol_len;
    764   const char * host = NULL;
    765   const char * protocol = NULL;
    766   const char * path = NULL;
    767 
    768   tmp = tr_strndup (url_in, len);
    769   if ((pch = strstr (tmp, "://")))
    770     {
    771       *pch = '\0';
    772       protocol = tmp;
    773       protocol_len = (size_t) (pch - protocol);
    774       pch += 3;
    775       if ((n = strcspn (pch, ":/")))
    776         {
    777           const int havePort = pch[n] == ':';
    778           host = pch;
    779           host_len = n;
    780           pch += n;
    781           if (pch && *pch)
    782             *pch++ = '\0';
    783           if (havePort)
    784             {
    785               char * end;
    786               port = strtol (pch, &end, 10);
    787               pch = end;
    788             }
    789           path = pch;
    790         }
    791     }
    792 
    793   err = !host || !path || !protocol;
    794 
    795   if (!err && !port)
    796     {
    797       if (!strcmp (protocol, "udp")) port = 80;
    798       else if (!strcmp (protocol, "ftp")) port = 21;
    799       else if (!strcmp (protocol, "sftp")) port = 22;
    800       else if (!strcmp (protocol, "http")) port = 80;
    801       else if (!strcmp (protocol, "https")) port = 443;
    802     }
    803 
    804   if (!err)
    805     {
    806       if (setme_protocol) *setme_protocol = tr_strndup (protocol, protocol_len);
    807 
    808       if (setme_host){ ((char*)host)[-3] = ':'; *setme_host =
    809                         tr_strndup (host, host_len); }
    810 
    811       if (setme_path){ if (!*path) *setme_path = tr_strdup ("/");
    812                        else if (path[0] == '/') *setme_path = tr_strdup (path);
    813                        else { ((char*)path)[-1] = '/'; *setme_path = tr_strdup (path - 1); } }
    814 
    815       if (setme_port) *setme_port = port;
    816     }
    817 
     732static int
     733parse_port (const char * port,
     734            size_t       port_len)
     735{
     736  char * tmp = tr_strndup (port, port_len);
     737  char * end;
     738
     739  long port_num = strtol (tmp, &end, 10);
     740
     741  if (*end != '\0' || port_num <= 0 || port_num >= 65536)
     742    port_num = -1;
    818743
    819744  tr_free (tmp);
    820   return err;
     745
     746  return (int) port_num;
     747}
     748
     749static int
     750get_port_for_scheme (const char * scheme,
     751                     size_t       scheme_len)
     752{
     753  struct known_scheme
     754    {
     755      const char * name;
     756      int          port;
     757    };
     758
     759  static const struct known_scheme known_schemes[] =
     760    {
     761      { "udp",    80 },
     762      { "ftp",    21 },
     763      { "sftp",   22 },
     764      { "http",   80 },
     765      { "https", 443 },
     766      { NULL,      0 }
     767    };
     768
     769  for (const struct known_scheme * s = known_schemes; s->name != NULL; ++s)
     770    {
     771      if (scheme_len == strlen (s->name) && memcmp (scheme, s->name, scheme_len) == 0)
     772        return s->port;
     773    }
     774
     775  return -1;
     776}
     777
     778bool
     779tr_urlParse (const char  * url,
     780             size_t        url_len,
     781             char       ** setme_scheme,
     782             char       ** setme_host,
     783             int         * setme_port,
     784             char       ** setme_path)
     785{
     786  if (url_len == TR_BAD_SIZE)
     787    url_len = strlen (url);
     788
     789  const char * scheme = url;
     790  const char * scheme_end = tr_memmem (scheme, url_len, "://", 3);
     791  if (scheme_end == NULL)
     792    return false;
     793
     794  const size_t scheme_len = scheme_end - scheme;
     795  if (scheme_len == 0)
     796    return false;
     797
     798  url += scheme_len + 3;
     799  url_len -= scheme_len + 3;
     800
     801  const char * authority = url;
     802  const char * authority_end = memchr (authority, '/', url_len);
     803  if (authority_end == NULL)
     804    authority_end = authority + url_len;
     805
     806  const size_t authority_len = authority_end - authority;
     807  if (authority_len == 0)
     808    return false;
     809
     810  url += authority_len;
     811  url_len -= authority_len;
     812
     813  const char * host_end = memchr (authority, ':', authority_len);
     814
     815  const size_t host_len = host_end != NULL ? host_end - authority : authority_len;
     816  if (host_len == 0)
     817    return false;
     818
     819  const size_t port_len = host_end != NULL ? authority_end - host_end - 1 : 0;
     820
     821  if (setme_scheme != NULL)
     822    *setme_scheme = tr_strndup (scheme, scheme_len);
     823
     824  if (setme_host != NULL)
     825    *setme_host = tr_strndup (authority, host_len);
     826
     827  if (setme_port != NULL)
     828    *setme_port = port_len > 0 ? parse_port (host_end + 1, port_len)
     829                               : get_port_for_scheme (scheme, scheme_len);
     830
     831  if (setme_path != NULL)
     832    {
     833      if (url[0] == '\0')
     834        *setme_path = tr_strdup ("/");
     835      else
     836        *setme_path = tr_strndup (url, url_len);
     837    }
     838
     839  return true;
    821840}
    822841
  • trunk/libtransmission/utils.h

    r14633 r14639  
    360360bool tr_addressIsIP (const char * address);
    361361
    362 /** @brief return true if the url is a http or https url that Transmission understands */
     362/** @brief return true if the url is a http or https or UDP url that Transmission understands */
    363363bool tr_urlIsValidTracker (const char * url) TR_GNUC_NONNULL (1);
    364364
    365 /** @brief return true if the url is a [ http, https, ftp, ftps ] url that Transmission understands */
     365/** @brief return true if the url is a [ http, https, ftp, sftp ] url that Transmission understands */
    366366bool tr_urlIsValid (const char * url, size_t url_len) TR_GNUC_NONNULL (1);
    367367
    368368/** @brief parse a URL into its component parts
    369     @return zero on success or an error number if an error occurred */
    370 int tr_urlParse (const char * url,
     369    @return True on success or false if an error occurred */
     370bool tr_urlParse (const char * url,
    371371                  size_t       url_len,
    372372                  char      ** setme_scheme,
Note: See TracChangeset for help on using the changeset viewer.