1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <ctype.h>
6 
7 #ifndef _POSIX_HOST_NAME_MAX
8 #define _POSIX_HOST_NAME_MAX 255
9 #endif
10 
11 /* define macros and variable for using the eina logging system  */
12 #define EFREET_MODULE_LOG_DOM /* no logging in this file */
13 
14 #include "Efreet.h"
15 #include "efreet_private.h"
16 
17 /* The URI standard is at http://tools.ietf.org/html/std66 */
18 
19 EAPI Efreet_Uri *
efreet_uri_decode(const char * full_uri)20 efreet_uri_decode(const char *full_uri)
21 {
22     Efreet_Uri *uri;
23     const char *p;
24     char scheme[64], authority[_POSIX_HOST_NAME_MAX], path[PATH_MAX];
25     char *sep;
26     int i = 0;
27 
28     EINA_SAFETY_ON_NULL_RETURN_VAL(full_uri, NULL);
29 
30     /* An uri should be in the form <scheme>:[<authority>][<path>][<query>][<fragment>] */
31     sep = strchr(full_uri, ':');
32     if (!sep) return NULL;
33     /* check if we have a Windows PATH, that is a letter follow by a colon */
34     if ((sep - full_uri) == 1) return NULL;
35 
36     memset(scheme, 0, 64);
37     memset(authority, 0, _POSIX_HOST_NAME_MAX);
38     memset(path, 0, PATH_MAX);
39 
40     /* parse scheme */
41     p = full_uri;
42     for (i = 0; *p != ':' && *p != '\0' && i < (64 - 1); p++, i++)
43          scheme[i] = *p;
44     if (i == 0) return NULL; /* scheme is required */
45     scheme[i] = '\0';
46 
47     /* parse authority */
48     p++;
49     if (*p == '/')
50     {
51         p++;
52         if (*p == '/')
53         {
54             p++;
55             for (i = 0; *p != '/' && *p != '?' && *p != '#' && *p != '\0' && i < (_POSIX_HOST_NAME_MAX - 1); p++, i++)
56                 authority[i] = *p;
57             authority[i] = '\0';
58         }
59         else /* It's a path, let path parser handle the leading slash */
60             p--;
61     }
62     else
63         authority[0] = '\0';
64 
65     /* parse path */
66     /* See http://www.faqs.org/rfcs/rfc1738.html for the escaped chars */
67     for (i = 0; *p != '\0' && i < (PATH_MAX - 1); i++, p++)
68     {
69         if (*p == '%')
70         {
71             path[i] = *(++p);
72             path[i + 1] = *(++p);
73             path[i] = (char)strtol(&(path[i]), NULL, 16);
74             path[i + 1] = '\0';
75         }
76         else
77             path[i] = *p;
78     }
79 
80     uri = NEW(Efreet_Uri, 1);
81     if (!uri) return NULL;
82 
83     uri->protocol = eina_stringshare_add(scheme);
84     uri->hostname = eina_stringshare_add(authority);
85     uri->path = eina_stringshare_add(path);
86 
87     return uri;
88 }
89 
90 EAPI const char *
efreet_uri_encode(Efreet_Uri * uri)91 efreet_uri_encode(Efreet_Uri *uri)
92 {
93     char dest[PATH_MAX * 3 + 4];
94     const char *p;
95     int i;
96 
97     EINA_SAFETY_ON_NULL_RETURN_VAL(uri, NULL);
98     EINA_SAFETY_ON_NULL_RETURN_VAL(uri->path, NULL);
99     EINA_SAFETY_ON_NULL_RETURN_VAL(uri->protocol, NULL);
100 
101     memset(dest, 0, PATH_MAX * 3 + 4);
102     snprintf(dest, strlen(uri->protocol) + 4, "%s://", uri->protocol);
103 
104     /* Most app doesn't handle the hostname in the uri so it's put to NULL */
105     for (i = strlen(uri->protocol) + 3, p = uri->path; *p != '\0'; p++, i++)
106     {
107         if (isalnum(*p) || strchr("/$-_.+!*'()", *p))
108             dest[i] = *p;
109         else
110         {
111             snprintf(&(dest[i]), 4, "%%%02X", (unsigned char) *p);
112             i += 2;
113         }
114     }
115 
116     return eina_stringshare_add(dest);
117 }
118 
119 EAPI void
efreet_uri_free(Efreet_Uri * uri)120 efreet_uri_free(Efreet_Uri *uri)
121 {
122     if (!uri) return;
123 
124     IF_RELEASE(uri->protocol);
125     IF_RELEASE(uri->path);
126     IF_RELEASE(uri->hostname);
127     FREE(uri);
128 }
129