mirror of https://github.com/ericonr/purr-c.git
Split scheme detection logic, use where possible.
Avoid parsing URLs in multiple places.
This commit is contained in:
parent
d95fdcddd6
commit
01eaa937fe
40
gemi.c
40
gemi.c
|
@ -114,9 +114,14 @@ int main(int argc, char **argv)
|
|||
.debug = debug, .no_strip = no_strip,
|
||||
.type = GEMINI_CONN};
|
||||
rv = send_and_receive(&ci);
|
||||
|
||||
// free resources
|
||||
bearssl_free_certs(&btas, num_ta);
|
||||
close(socket);
|
||||
|
||||
bearssl_free_certs(&btas, num_ta);
|
||||
if (rv == EXIT_FAILURE) {
|
||||
goto early_out;
|
||||
}
|
||||
|
||||
// generic way of outputting data:
|
||||
// - if using FILE backend, offset is 0 and nothing happens
|
||||
|
@ -130,32 +135,49 @@ int main(int argc, char **argv)
|
|||
fputs("Input desired link (starts at 0): ", stderr);
|
||||
int in;
|
||||
int err = scanf("%d", &in);
|
||||
if (err != 1) {
|
||||
if (err == EOF) {
|
||||
// exit cleanly on EOF
|
||||
goto early_out;
|
||||
} else if (err != 1) {
|
||||
// TODO: ? option to show all found links
|
||||
fputs("\nBad input!\n", stderr);
|
||||
rv = EXIT_FAILURE;
|
||||
goto early_out;
|
||||
}
|
||||
fprintf(stderr, "Selected link: %d\n", in);
|
||||
|
||||
// if it leaves this part, it's a bad exit
|
||||
rv = EXIT_FAILURE;
|
||||
if (in >= 0 && in < n) {
|
||||
// valid link number
|
||||
char *new_path = get_gemini_node_by_n(head, in)->path;
|
||||
fprintf(stderr, "Selected link: %s\n", new_path);
|
||||
char *new_argv[] = {progpath, "-b", new_path, NULL};
|
||||
if (strstr(new_path, "gemini://") == NULL) {
|
||||
// in is a valid link number
|
||||
char *new_arg = get_gemini_node_by_n(head, in)->path;
|
||||
fprintf(stderr, "Selected link: %s\n", new_arg);
|
||||
char *new_argv[] = {progpath, "-b", new_arg, NULL};
|
||||
int new_portn = get_port_from_link(new_arg);
|
||||
if (new_portn == NO_INFO_PORT) {
|
||||
// link is not absolute path
|
||||
// TODO: path resolution
|
||||
// TODO: better error msgs
|
||||
char *new_url = calloc(1, strlen(url) + strlen(new_path) + 1);
|
||||
// TODO: treat error codes from server -> bad links (lacking trailing /, for example),
|
||||
// can probably be solved locally with a smarter client
|
||||
// Perhaps make header parsing a virtual function kind of thing?
|
||||
char *new_url = calloc(1, strlen(url) + strlen(new_arg) + 1);
|
||||
if (new_url == NULL) {
|
||||
perror("calloc()");
|
||||
return rv;
|
||||
}
|
||||
sprintf(new_url, "%s%s", url, new_path);
|
||||
sprintf(new_url, "%s%s", url, new_arg);
|
||||
new_argv[2] = new_url;
|
||||
} else if (new_portn != GEMINI_PORT) {
|
||||
fputs("\nUnsupported protocol!\n", stderr);
|
||||
goto early_out;
|
||||
}
|
||||
|
||||
execvp(progpath, new_argv);
|
||||
} else {
|
||||
fputs("\nBad number!\n", stderr);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2
gemini.h
2
gemini.h
|
@ -9,7 +9,7 @@ struct gemini_link_node {
|
|||
};
|
||||
|
||||
/* gemini.c */
|
||||
int get_links_from_gmi(const char*, struct gemini_link_node **);
|
||||
int get_links_from_gmi(const char *, struct gemini_link_node **);
|
||||
struct gemini_link_node *get_gemini_node_by_n(struct gemini_link_node *, int);
|
||||
|
||||
#endif // __GEMINI_H_
|
||||
|
|
3
purr.h
3
purr.h
|
@ -10,6 +10,8 @@
|
|||
#define HTTP_PORT 80
|
||||
#define HTTPS_PORT 443
|
||||
#define GEMINI_PORT 1965
|
||||
#define UNKNOWN_PORT -2
|
||||
#define NO_INFO_PORT -1
|
||||
|
||||
#define HEADER_MAX_LEN 8192
|
||||
|
||||
|
@ -54,6 +56,7 @@ int socket_read(void *, uint8_t *, size_t);
|
|||
int socket_write(void *, const uint8_t *, size_t);
|
||||
|
||||
/* urls.c */
|
||||
int get_port_from_link(const char *);
|
||||
int clean_up_link(const char *, char **, char **, char **, char **);
|
||||
int get_encryption_params(char *, uint8_t **, uint8_t **);
|
||||
int host_connect(const char *, const char *, bool);
|
||||
|
|
13
tests.c
13
tests.c
|
@ -82,6 +82,19 @@ int main()
|
|||
free(path); path = NULL;
|
||||
free(port); port = NULL;
|
||||
|
||||
dirty = "hello.com";
|
||||
portn = clean_up_link(dirty, &scheme, &clean, &path, &port);
|
||||
rv = compare_strings("http://", scheme, "clean_up_link") ? 1 : rv;
|
||||
rv = compare_strings("hello.com", clean, "clean_up_link") ? 1 : rv;
|
||||
rv = compare_strings("/", path, "clean_up_link") ? 1 : rv;
|
||||
rv = compare_strings("80", port, "clean_up_link") ? 1 : rv;
|
||||
assert(portn == HTTP_PORT);
|
||||
|
||||
free(scheme); scheme = NULL;
|
||||
free(clean); clean = NULL;
|
||||
free(path); path = NULL;
|
||||
free(port); port = NULL;
|
||||
|
||||
dirty = "https://bsd.ac/paste.html#sieqaqk_73fe_df51";
|
||||
portn = clean_up_link(dirty, &scheme, &clean, &path, &port);
|
||||
rv = compare_strings("https://", scheme, "clean_up_link") ? 1 : rv;
|
||||
|
|
62
urls.c
62
urls.c
|
@ -16,6 +16,32 @@ static const char *http_sch = "http://";
|
|||
static const char *https_sch = "https://";
|
||||
static const char *gemini_sch = "gemini://";
|
||||
|
||||
int get_port_from_link(const char *url)
|
||||
{
|
||||
int portn = -1;
|
||||
const char *scheme_separator = strstr(url, "://");
|
||||
if (scheme_separator) {
|
||||
// found protocol specified, otherwise return error
|
||||
if (scheme_separator - url + 3 > MAX_SHORTY_LEN) {
|
||||
fputs("get_port_from_link(): scheme is too long!\n", stderr);
|
||||
return portn;
|
||||
}
|
||||
size_t scheme_len = scheme_separator - url + 3;
|
||||
if (memcmp(url, https_sch, scheme_len) == 0) {
|
||||
portn = HTTPS_PORT;
|
||||
} else if (memcmp(url, http_sch, scheme_len) == 0) {
|
||||
portn = HTTP_PORT;
|
||||
} else if (memcmp(url, gemini_sch, scheme_len) == 0) {
|
||||
portn = GEMINI_PORT;
|
||||
} else {
|
||||
portn = UNKNOWN_PORT;
|
||||
fputs("clean_up_link(): unknown protocol!\n", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
return portn;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function cleans up the link in dirty, providing each of its parts in the
|
||||
* buffers pointed to by schemep, cleanp, pathp and portp.
|
||||
|
@ -46,32 +72,24 @@ int clean_up_link(const char *dirty, char **schemep, char **cleanp, char **pathp
|
|||
*portp = port;
|
||||
|
||||
// detect protocol, remove protocol prefix
|
||||
const char *scheme_separator = strstr(dirty, "://");
|
||||
const char *start_link = NULL;
|
||||
if (scheme_separator == NULL) {
|
||||
// no protocol specified, default to HTTP
|
||||
portn = get_port_from_link(dirty);
|
||||
bool get_scheme_len = true;
|
||||
if (portn == UNKNOWN_PORT) {
|
||||
fputs("clean_up_link(): unknown protocol!\n", stderr);
|
||||
return portn;
|
||||
} else if (portn == NO_INFO_PORT || portn == HTTP_PORT) {
|
||||
// no scheme defined -> default to HTTP
|
||||
// if no scheme defined -> no need to advance scheme
|
||||
get_scheme_len = portn != NO_INFO_PORT;
|
||||
portn = HTTP_PORT;
|
||||
strcpy(scheme, http_sch);
|
||||
start_link = dirty;
|
||||
} else {
|
||||
if (scheme_separator - dirty + 3 > MAX_SHORTY_LEN) {
|
||||
fputs("clean_up_link(): scheme is too long!\n", stderr);
|
||||
return -1;
|
||||
}
|
||||
memcpy(scheme, dirty, scheme_separator - dirty + 3);
|
||||
if (strcmp(scheme, https_sch) == 0) {
|
||||
portn = HTTPS_PORT;
|
||||
} else if (strcmp(scheme, http_sch) == 0) {
|
||||
portn = HTTP_PORT;
|
||||
} else if (strcmp(scheme, gemini_sch) == 0) {
|
||||
portn = GEMINI_PORT;
|
||||
} else {
|
||||
fputs("clean_up_link(): unknown protocol!\n", stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
start_link = dirty + strlen(scheme);
|
||||
} else if (portn == HTTPS_PORT) {
|
||||
strcpy(scheme, https_sch);
|
||||
} else if (portn == GEMINI_PORT) {
|
||||
strcpy(scheme, gemini_sch);
|
||||
}
|
||||
start_link = dirty + (get_scheme_len ? strlen(scheme) : 0);
|
||||
|
||||
// maximum size necessary
|
||||
// use strncpy for portability
|
||||
|
|
Loading…
Reference in New Issue