libmp/src/url.c

204 lines
4.2 KiB
C
Raw Normal View History

2024-06-20 00:34:32 +00:00
#include "../include/error.h"
#include "../include/util.h"
#include "../include/url.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
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);
}