libmp/src/url.c

227 lines
4.7 KiB
C
Raw Normal View History

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