#include #include #include "url.h" #define SET_STR(segment) \ (segment) = malloc(i - start + 1); \ strncpy((segment), s + start, i - start); #define MOVE(amount) \ i += (amount); \ start = i; #define SET_AT_END(segment) \ if (cur == '\0') { \ state = END; \ if (i - 1 > start) { \ SET_STR(segment); \ } \ } enum state { SCHEME, HOST, PORT, PATH, QUERY, FRAGMENT, END }; int parse_url(struct url *url, char *s) { int i = 0; // index into *s int start = 0; // index of current mode start enum state state = SCHEME; char cur; while (i < MAX_URL_LENGTH) { cur = s[i]; if (cur == ' ') return INVALID_CHARACTER; switch (state) { case SCHEME: if (cur == ':') { state = HOST; SET_STR(url->scheme); MOVE(3); // skip the '://' } SET_AT_END(url->scheme); break; case HOST: if (cur == ':') { state = PORT; SET_STR(url->host); MOVE(1); } if (cur == '/') { state = PATH; SET_STR(url->host); MOVE(0); } SET_AT_END(url->host); break; case PORT: if (cur == '/') { state = PATH; char *port; SET_STR(port); url->port = atoi(port); MOVE(0); } if (cur == '\0') { state = END; char *port; SET_STR(port); url->port = atoi(port); } break; case PATH: if (cur == '?') { state = QUERY; SET_STR(url->path); MOVE(0); } if (cur == '#') { state = FRAGMENT; SET_STR(url->path); MOVE(0); } SET_AT_END(url->path); break; case QUERY: if (cur == '#') { state = FRAGMENT; SET_STR(url->query); MOVE(0); } SET_AT_END(url->query); break; case FRAGMENT: if (cur == '\0') { state = END; SET_STR(url->fragment); MOVE(0); } break; case END: break; } i++; if (cur == '\0') break; if (state == END) break; } if (url->host == NULL) return MISSING_HOST; if (url->port == 0) return MISSING_PORT; if (url->path == NULL) { url->path = malloc(2); strcpy(url->path, "/"); } return 0; } struct url *init_url(void) { struct url *url = malloc(sizeof(struct url)); url->scheme = NULL; url->host = NULL; url->port = 2693; url->path = NULL; url->query = NULL; url->fragment = NULL; return url; } void free_url(struct url *url) { free(url->scheme); free(url->host); free(url->path); free(url->fragment); free(url->query); free(url); } int len_url(struct url *url) { int len = 0; len += url->scheme != NULL ? strlen(url->scheme) : 0; len += url->host != NULL ? strlen(url->host) : 0; len += sizeof(url->port); len += url->path != NULL ? strlen(url->path) : 0; len += url->query != NULL ? strlen(url->query) : 0; len += url->fragment != NULL ? strlen(url->fragment) : 0; return len; }