#include #include #include #include #include #include #include #include "uri.h" size_t estrlcpy(char *dst, const char *src, size_t dstsize) { size_t n; n = strlcpy(dst, src, dstsize); if (n >= dstsize) { fputs("liburi: Buffer overflow\n", stderr); exit(1); } return n; } #define EURINOSCHEME 96 #define EURIBADSCHEME 97 #define EURIBADUSERINFO 98 #define EURIBADHOST 99 #define EURIBADIPLIT 100 int isschemechr(int c); int iuserinfochr(int c); int ishostchr(int c); int isportchr(int c); int isiplitchr(int c); int isipv6addresschr(int c); int isipvfuture(int c); int ispctencoded(int c); int isunreserved(int c); int isreserved(int c); int isgendelim(int c); int issubdelim(int c); int isschemechr(int c) { return isalpha(c) || isdigit(c) || c == '+' || c == '.' || c == '-'; } int isuserinfochr(int c) { return isunreserved(c) || issubdelim(c) || c == ':'; } int isiplitchr(int c) { // return c == '[' || } int isipv6chr(int c) { } int ispchar(int c) { return isunreserved(c) || ispctencoded(c) || issubdelim(c) || c == ':' || c == '@'; } int isquerychr(int c) { return ispchar(c) || c == '/' || c == '?'; } int isfragmentchr(int c) { return ispchar(c) || c == '/' || c == '?'; } int ispctencoded(int c) { return isxdigit(c) || c == '%'; } int isunreserved(int c) { return isalpha(c) || isdigit(c) || c == '-' || c == '.' || c == '_' || c == '~'; } int isreserved(int c) { return isgendelim(c) || issubdelim(c); } int isgendelim(int c) { return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'; } int issubdelim(int c) { return c == '!' || c == '$' || c == '&' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || c == '='; } char * parsescheme(const char *scheme) { char *Scheme; int i = 0, c; if (!isalpha(scheme[0])) { goto err; } Scheme = strdup(scheme); while((c = Scheme[i])) { if (!isschemechr(c)) goto err; Scheme[i] = tolower(c); i++; } if (i != 0) goto done; err: errno = EURIBADSCHEME; return NULL; done: return Scheme; } Userinfo * parseuserinfo(const char *userinfo) { Userinfo *Userinfo; char username[USERINFO_USERNAME_MAX]; char password[USERINFO_PASSWORD_MAX]; int i = 0, usernamelen = 0, c; Userinfo = malloc(sizeof(struct Userinfo)); if (Userinfo == NULL) { free(Userinfo); return NULL; } while((c = userinfo[i])) { if (!isuserinfochr(c)) { free(Userinfo); errno = EURIBADUSERINFO; return NULL; } if (c == ':') { username[i] = 0; i++; usernamelen = i; goto password; } username[i] = c; i++; } goto done; password: while((c = userinfo[i])) { if (!isuserinfochr(c)) { free(Userinfo); errno = EURIBADUSERINFO; return NULL; } password[i - usernamelen] = c; i++; } done: strcpy(Userinfo->username, username); strcpy(Userinfo->password, password); return Userinfo; } /* char * parseipliteral(const char *iplit) { char *IPLit; int i = 0, c; if (iplit[0] != '[') { errno = EURIBADIPLIT; return NULL; } IPLit = strdup(iplit); while((c = IPLit[i])) { if (!isiplitchr(c)) goto err; Scheme[i] = tolower(c); i++; } if (i != 0) goto done; err: errno = EURIBADSCHEME; return NULL; } char * parsehost(const char *host) { char *Host; if (host[0] == '[') { return parseipliteral(host); } } */ Authority * parseauthority(const char *authority) { char userinfo[USERINFO_MAX]; char host[AUTHORITY_HOST_MAX]; char port[AUTHORITY_PORT_MAX]; Userinfo *Userinfo; Authority *Authority; const char *p = authority, *t; Authority = malloc(sizeof(struct Authority)); if (Authority == NULL) { free(Authority); return NULL; } t = strchr(authority, '@'); if (t) { strncpy(userinfo, p, t - p); userinfo[t - p + 1] = 0; Userinfo = parseuserinfo(userinfo); strcpy(Authority->username, Userinfo->username); strcpy(Authority->password, Userinfo->password); p = t + 1; } t = strchr(p, ':'); if (t) { strncpy(host, p, t - p); host[t - p + 1] = 0; estrlcpy(port, t + 1, sizeof(port)); } else { estrlcpy(host, p, sizeof(host)); } strcpy(Authority->host, host); strcpy(Authority->port, port); return Authority; } /* Query * parsequery(const char *query) { Query *Query; Query = malloc(sizeof(struct Query)); if (Query == NULL) { free(Query); return NULL; } Query->params = malloc(1 * sizeof(ENTRY)); Query->params[0] = malloc(sizeof(ENTRY)); Query->params[0]->key = "foo"; Query->params[0]->data = "bar"; Query->len = 1; return Query; } */ Uri * parseuri(const char *uri) { char scheme[SCHEME_MAX]; char authority[AUTHORITY_MAX]; char path[PATH_MAX]; char query[QUERY_MAX]; Authority *Authority; Uri *Uri; const char *p = uri, *t; char *s; int c; Uri = malloc(sizeof(struct Uri)); if (Uri == NULL) { free(Uri); return NULL; } t = strchr(uri, ':'); if (t == NULL) { free(Uri); errno = EURINOSCHEME; return NULL; } strncpy(scheme, p, t - p); scheme[t - p] = 0; s = parsescheme(scheme); if (s == NULL) { free(s); free(Uri); return NULL; } estrlcpy(Uri->scheme, s, sizeof(Uri->scheme)); p = t + 1; if (*p == '/') { if (*(p + 1) != '/') goto path; p = p + 2; t = p + strcspn(p, "/#?"); strncpy(authority, p, t - p); authority[t - p] = 0; Authority = parseauthority(authority); if(Authority == NULL) { free(Authority); free(Uri); return NULL; } strcpy(Uri->username, Authority->username); strcpy(Uri->password, Authority->password); strcpy(Uri->host, Authority->host); strcpy(Uri->port, Authority->port); p = t; switch(*t) { case '/': goto path; case '?': goto query; case '#': goto fragment; } } path: t = p + strcspn(p, "?#"); if (t == p) goto query; strncpy(Uri->path, p, t - p); Uri->path[t - p] = 0; p = t; query: if (*p != '?') goto fragment; t = p + strcspn(p, "#"); if (t == p) goto fragment; strncpy(query, p + 1, t - p - 1); query[t - p - 1] = 0; //Uri->query = parsequery(query); strcpy(Uri->query, query); p = t; fragment: if (*p != '#') goto done; estrlcpy(Uri->fragment, p + 1, sizeof(Uri->fragment)); done: return Uri; }