Changeset: e33753ba0353 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=e33753ba0353
Modified Files:
        monetdb5/modules/atoms/url.c
        sql/test/BugTracker-2012/Tests/url_script_test.Bug-2972.stable.out
Branch: Jan2014
Log Message:

Reimplemented URL parsing, and cleaned up code and mistakes.


diffs (truncated from 1243 to 300 lines):

diff --git a/monetdb5/modules/atoms/url.c b/monetdb5/modules/atoms/url.c
--- a/monetdb5/modules/atoms/url.c
+++ b/monetdb5/modules/atoms/url.c
@@ -57,519 +57,133 @@
 #include "mal.h"
 #include "mal_exception.h"
 
-#if 0
-static void getword(char *word, char *line, char stop);
-static void plustospace(char *str);
-#endif
 static char x2c(char *what);
 
-/* COMMAND "getAnchor": Extract an anchor (reference) from the URL
- * SIGNATURE: getAnchor(url) : str; */
-static str
-url_getAnchor(str *retval, /* put string: pointer to char here. */
-               url Str1)          /* string: pointer to char. */
+/* SCHEME "://" AUTHORITY [ PATH ] [ "?" SEARCH ] [ "#" FRAGMENT ]
+ * AUTHORITY is: [ USER [ ":" PASSWORD ] "@" ] HOST [ ":" PORT ] */
+
+/* return pointer to string after the scheme and colon; input: pointer
+ * to start of URI */
+static const char *
+skip_scheme(const char *uri)
 {
-       str s, d;
-
-       if (Str1 == 0)
-               throw(ILLARG, "url.getAnchor", "url missing");
-       s = strchr(Str1, '#');
-       if (s == 0) 
-               s= (str) str_nil;
-       d = GDKstrdup(s);
-       if (d == NULL)
-               throw(MAL, "url.getAnchor", "Allocation failed");
-       *retval = d;
-       return MAL_SUCCEED;
+       if (('a' <= *uri && *uri <= 'z') || ('A' <= *uri && *uri <= 'Z')) {
+               uri++;
+               while (('a' <= *uri && *uri <= 'z') ||
+                          ('A' <= *uri && *uri <= 'Z') ||
+                          ('0' <= *uri && *uri <= '9') ||
+                          *uri == '+' || *uri == '-' || *uri == '.')
+                       uri++;
+               if (*uri == ':')
+                       return uri + 1;
+       }
+       return NULL;
 }
 
-/* COMMAND "getBasename": Extract the base of the last file name of the URL,
- *                        thus, excluding the file extension.
- * SIGNATURE: getBasename(str) : str; */
-static str
-url_getBasename(str *retval, url t)
+#define ishex(c) (('0' <= (c) && (c) <= '9') || \
+                                 ('a' <= (c) && (c) <= 'f') || \
+                                 ('A' <= (c) && (c) <= 'F'))
+#define isreserved(c)  ((c) == ';' || (c) == '/' || (c) == '?' || \
+                                                (c) == ':' || (c) == '@' || 
(c) == '&' || \
+                                                (c) == '=' || (c) == '+' || 
(c) == '$' || \
+                                                (c) == ',')
+#define isunreserved(c) (('a' <= (c) && (c) <= 'z') || \
+                                                ('A' <= (c) && (c) <= 'Z') || \
+                                                ('0' <= (c) && (c) <= '9') || \
+                                                (c) == '-' || (c) == '_' || 
(c) == '.' || \
+                                                (c) == '!' || (c) == '~' || 
(c) == '*' || \
+                                                (c) == '\'' || (c) == '(' || 
(c) == ')')
+
+/* return pointer to string after the authority, filling in pointers
+ * to start of user, password, host, and port, if provided; input:
+ * result of skip_scheme() */
+static const char *
+skip_authority(const char *uri, const char **userp, const char **passp, const 
char **hostp, const char **portp)
 {
-       str d = 0, s;
+       const char *user = NULL, *pass = NULL, *host = NULL, *port = NULL;
 
-       if (t == 0)
-               throw(ILLARG, "url.getBasename", "url missing");
-       s = strrchr(t, '/');
-       if (s)
-               s++;
-       else
-               s = (str) str_nil;
-       d = GDKstrdup(s);
-       if (d == NULL)
-               throw(MAL, "url.getBasename", "Allocation failed");
-       s = strchr(d, '.');
-       if (s)
-               *s = 0;
-       *retval = d;
-       return MAL_SUCCEED;
+       if (uri[0] == '/' && uri[1] == '/') {
+               uri += 2;
+               user = host = uri;
+               while (isunreserved(*uri) ||
+                          (*uri == '%' && ishex(uri[1]) && ishex(uri[2])) ||
+                          *uri == ';' || *uri == ':' || *uri == '=' || *uri == 
'+'|| *uri == '$' || *uri == ',' ||
+                          *uri == '@') {
+                       if (*uri == ':') {
+                               if (user == host)
+                                       port = pass = uri + 1;
+                               else
+                                       port = uri + 1;
+                       } else if (*uri == '@')
+                               host = uri + 1;
+                       uri += *uri == '%' ? 3 : 1;
+               }
+               if (user == host) {
+                       /* no "@", so no user info */
+                       if (userp)
+                               *userp = NULL;
+                       if (passp)
+                               *passp = NULL;
+               } else {
+                       if (*userp)
+                               *userp = user;
+                       if (*passp)
+                               *passp = pass;
+               }
+               if (portp)
+                       *portp = port;
+               if (hostp)
+                       *hostp = host;
+               return uri;
+       }
+       return NULL;
 }
 
-#if 0
-/* COMMAND "getContent": Retrieve the file referenced
- * SIGNATURE: getContent(str) : str; */
-static str
-url_getContent(str *retval, /* put string: pointer to char here. */
-               url Str1)           /* string: pointer to char. */
+/* return pointer to string after the path, filling in pointer to
+ * start of last component and extension of that component; input:
+ * result of skip_authority() */
+static const char *
+skip_path(const char *uri, const char **basep, const char **extp)
 {
-       /* TODO: getContent should not return a string */
-       if (!Str1)
-               throw(ILLARG, "url.getContent", "url missing");
-       strcpy(*retval, "functions not implemented");
-       return MAL_SUCCEED;
-}
-#endif
+       const char *base = NULL, *ext = NULL;
 
-/* COMMAND "getContext": Extract the path context from the URL
- * SIGNATURE: getContext(str) : str; */
-static str
-url_getContext(str *retval, url Str1)
-{
-       const char *s;
-       str d;
-
-       if (Str1 == 0)
-               throw(ILLARG, "url.getContext", "url missing");
-
-       s = strstr(Str1, "://");
-       if (s)
-               s += 3;
-       else
-               s = Str1;
-
-       s = strchr(s, '/');
-       if (s == 0)
-               s = str_nil;
-       d = GDKstrdup(s);
-       if (d == NULL)
-               throw(MAL, "url.getContext", "Allocation failed");
-       *retval = d;
-       return MAL_SUCCEED;
+       if (*uri == '/') {
+               uri++;
+               base = uri;
+               while (isunreserved(*uri) ||
+                          (*uri == '%' && ishex(uri[1]) && ishex(uri[2])) ||
+                          *uri == ':' || *uri == '@' || *uri == '&' || *uri == 
'=' || *uri == '+' || *uri == '$' || *uri == ',' ||
+                          *uri == ';' ||
+                          *uri == '/') {
+                       if (*uri == '/') {
+                               base = uri + 1;
+                               ext = NULL;
+                       } else if (*uri == '.' && ext == NULL && uri != base) {
+                               ext = uri;
+                       }
+                       uri += *uri == '%' ? 3 : 1;
+               }
+       }
+       if (basep)
+               *basep = base;
+       if (extp)
+               *extp = ext;
+       return uri;
 }
 
-#if 0
-/* COMMAND "getDirectory": Extract the directory names from the URL
- * SIGNATURE: getDirectory(str) : bat[int,str]; */
-static str
-url_getDirectory(BAT **retval, /* put pointer to BAT[int,str] record here. */
-               url t)
+/* return pointer to string after the search string; input: result of
+ * skip_path() */
+static const char *
+skip_search(const char *uri)
 {
-       char buf[1024];
-       char *s;
-       int i = 0, k = 0;
-       BAT *b = NULL;
-
-       if (t == 0)
-               throw(ILLARG, "url.getDirectory", "url missing");
-
-       while (*t && *t != ':')
-               t++;
-       t++;
-       if (*t != '/')
-               goto getDir_done;
-       t++;
-       if (*t != '/')
-               goto getDir_done;
-       t++;
-       while (*t && *t != '/')
-               t++;
-       b = BATnew(TYPE_int, TYPE_str, 40);
-       if (b == 0)
-               throw(MAL, "url.getDirectory", "could not create BAT");
-
-       s = buf;
-       for (t++; *t; t++) {
-               if (*t == '/') {
-                       *s = 0;
-                       BUNins(b, &k, buf, FALSE);
-                       k++;
-                       s = buf;
-                       *s = 0;
-                       i = 0;
-                       continue;
+       if (*uri == '?') {
+               uri++;
+               while (isreserved(*uri) || isunreserved(*uri) ||
+                          (*uri == '%' && ishex(uri[1]) && ishex(uri[2]))) {
+                       uri += *uri == '%' ? 3 : 1;
                }
-               *s++ = *t;
-               if (i++ == 1023)
-                       throw(PARSE, "url.getDirectory","server name too long");
        }
-getDir_done:
-       BATrename(b,"dir_name");
-       BATroles(b,"dir","name");
-       BATmode(b,TRANSIENT);
-       *retval= b;
-       return MAL_SUCCEED;
-}
-#endif
-
-/* COMMAND "getDomain": Extract the Internet domain from the URL
- * SIGNATURE: getDomain(str) : str; */
-str
-URLgetDomain(str *retval, str *u)
-{
-       char buf[1024];
-       char *b, *d, *s = buf;
-       int i = 0;
-       url t= *u;
-
-       *retval = 0;
-       s = (str)str_nil;
-       if (t == 0)
-               throw(ILLARG, "url.getDomain", "domain missing");
-       while (*t && *t != ':')
-               t++;
-       t++;
-       if (*t != '/')
-               goto getDomain_done;
-       t++;
-       if (*t != '/')
-               goto getDomain_done;
-       t++;
-       b = buf;
-       d = 0;
-       for (; *t && *t != '/' && *t != ':' && *t != '?' && *t != '#'; t++) {
-               if (*t == '.')
-                       d = b;
-               *b++ = *t;
-               if (i++ == 1023)
-                       throw(PARSE, "url.getDomain", "server name too long\n");
-       }
-       *b = 0;
-       if (d)
-               s = d + 1;
-getDomain_done:
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to