#include "../include/error.h" #include "../include/util.h" #include "../include/url.h" #include #include #include #include char valid_path[] = "-._~:/?#[]@!$&'()*+,;%="; typedef enum lm_state { URL_PROTOCOL_0 = 0, URL_SPLIT_1 = 1, URL_HOST_2 = 2, URL_PATH_3 = 3, } lm_state_t; uint16_t lm_url_default(char *protocol){ if(eq(protocol, "ftp")) return 21; else if(eq(protocol, "ftps")) return 990; else if(eq(protocol, "http")) return 80; else if(eq(protocol, "https")) return 443; else if(eq(protocol, "mptp")) return 5858; return 0; } bool lm_url_parse(lm_url_t *url, char *str){ // clear out every variable bzero(url->protocol, sizeof(url->protocol)); url->host = NULL; url->path = NULL; url->port = 0; // stores the string size size_t strl = 0, index = 0, pos = 0; // make sure the URL string size is not too large // extra 4 for "://" and ":" if((strl = strlen(str)) > URL_PROTOCOL_MAX+URL_PATH_MAX+URL_HOST_MAX+4){ lm_error_set(LM_ERR_URLTooLarge); return false; } lm_state_t state = URL_PROTOCOL_0; char buffer[strl+1]; // temporary buffer bool ret = false; // return value // clear out the temporary buffer bzero(buffer, strl+1); while ((buffer[index] = *(str+pos)) != 0) { switch (state) { case URL_PROTOCOL_0: if(index > URL_PROTOCOL_MAX){ lm_error_set(LM_ERR_URLBadProtocol); goto end; } if (!is_letter(buffer[index]) && !is_digit(buffer[index]) && buffer[index] != ':'){ lm_error_set(LM_ERR_URLBadChar); goto end; } if(buffer[index] != ':') break; if(0 == index){ lm_error_set(LM_ERR_URLBadProtocol); goto end; } buffer[index] = 0; memcpy(url->protocol, buffer, index+1); goto next; case URL_SPLIT_1: if(index > 1){ lm_error_set(LM_ERR_URLBadProtocol); goto end; } if (buffer[index] != '/'){ lm_error_set(LM_ERR_URLBadChar); goto end; } if(index != 1) break; if(buffer[index-1] != '/' || buffer[index] != '/'){ lm_error_set(LM_ERR_URLBadProtocol); goto end; } goto next; case URL_HOST_2: if(index > URL_HOST_MAX){ lm_error_set(LM_ERR_URLHostLarge); goto end; } if (!is_letter(buffer[index]) && !is_digit(buffer[index]) && buffer[index] != '.' && buffer[index] != ':' && buffer[index] != '/'){ lm_error_set(LM_ERR_URLBadChar); goto end; } if(buffer[index] != '/') break; if(index == 0){ lm_error_set(LM_ERR_URLBadHost); goto end; } buffer[index] = 0; url->host = malloc((index+1)*sizeof(char)); memcpy(url->host, buffer, index+1); goto next; case URL_PATH_3: if(index > URL_PATH_MAX){ lm_error_set(LM_ERR_URLPathLarge); goto end; } if (!is_letter(buffer[index]) && !is_digit(buffer[index]) && !contains(valid_path, buffer[index])){ lm_error_set(LM_ERR_URLBadChar); goto end; } break; default: assert(false); } index++; pos++; continue; next: bzero(buffer, strl+1); state++; index = 0; pos++; } switch (state) { case URL_HOST_2: if(index == 0){ lm_error_set(LM_ERR_URLBadHost); goto end; } if(index > URL_HOST_MAX){ lm_error_set(LM_ERR_URLHostLarge); goto end; } url->host = malloc((index+1)*sizeof(char)); memcpy(url->host, buffer, index+1); url->path = malloc(2*sizeof(char)); url->path[0] = '/'; url->path[1] = 0; break; case URL_PATH_3: url->path = malloc((index+2)*sizeof(char)); url->path[0] = '/'; memcpy(url->path+1, buffer, index+1); break; default: lm_error_set(LM_ERR_URLEnd); goto end; } ret = true; end: if(!ret && NULL != url->host) free(url->host); if(!ret && NULL != url->path) free(url->path); return ret; } void lm_url_free(lm_url_t *url){ if(NULL != url->host) free(url->host); if(NULL != url->path) free(url->path); }