Navigation Menu

Skip to content

Commit

Permalink
http: Split HTTP redirect and cookie clear logic into helper functions
Browse files Browse the repository at this point in the history
This makes openconnect_obtain_cookie() shorter, and easier to follow.

Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
  • Loading branch information
cernekee committed Oct 27, 2012
1 parent 5ff8489 commit 3edcc28
Showing 1 changed file with 103 additions and 86 deletions.
189 changes: 103 additions & 86 deletions http.c
Expand Up @@ -591,14 +591,112 @@ int internal_parse_url(char *url, char **res_proto, char **res_host,
return 0;
}

static void clear_cookies(struct openconnect_info *vpninfo)
{
struct vpn_option *opt, *next;

for (opt = vpninfo->cookies; opt; opt = next) {
next = opt->next;

free(opt->option);
free(opt->value);
free(opt);
}
vpninfo->cookies = NULL;
}

/* Return value:
* < 0, on error
* = 0, on success (go ahead and retry with the latest vpninfo->{hostname,urlpath,port,...})
*/
static int handle_redirect(struct openconnect_info *vpninfo)
{
if (!strncmp(vpninfo->redirect_url, "https://", 8)) {
/* New host. Tear down the existing connection and make a new one */
char *host;
int port;
int ret;

free(vpninfo->urlpath);
vpninfo->urlpath = NULL;

ret = internal_parse_url(vpninfo->redirect_url, NULL, &host, &port, &vpninfo->urlpath, 0);
if (ret) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to parse redirected URL '%s': %s\n"),
vpninfo->redirect_url, strerror(-ret));
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
return ret;
}

if (strcasecmp(vpninfo->hostname, host) || port != vpninfo->port) {
free(vpninfo->hostname);
vpninfo->hostname = host;
vpninfo->port = port;

/* Kill the existing connection, and a new one will happen */
free(vpninfo->peer_addr);
vpninfo->peer_addr = NULL;
openconnect_close_https(vpninfo, 0);
clear_cookies(vpninfo);
} else
free(host);

free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;

return 0;
} else if (strstr(vpninfo->redirect_url, "://")) {
vpn_progress(vpninfo, PRG_ERR,
_("Cannot follow redirection to non-https URL '%s'\n"),
vpninfo->redirect_url);
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
return -EINVAL;
} else if (vpninfo->redirect_url[0] == '/') {
/* Absolute redirect within same host */
free(vpninfo->urlpath);
vpninfo->urlpath = strdup(vpninfo->redirect_url + 1);
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
return 0;
} else {
char *lastslash = NULL;
if (vpninfo->urlpath)
lastslash = strrchr(vpninfo->urlpath, '/');
if (!lastslash) {
free(vpninfo->urlpath);
vpninfo->urlpath = vpninfo->redirect_url;
vpninfo->redirect_url = NULL;
} else {
char *oldurl = vpninfo->urlpath;
*lastslash = 0;
vpninfo->urlpath = NULL;
if (asprintf(&vpninfo->urlpath, "%s/%s",
oldurl, vpninfo->redirect_url) == -1) {
int err = -errno;
vpn_progress(vpninfo, PRG_ERR,
_("Allocating new path for relative redirect failed: %s\n"),
strerror(-err));
return err;
}
free(oldurl);
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
}
return 0;
}
}

/* Return value:
* < 0, on error
* > 0, no cookie (user cancel)
* = 0, obtained cookie
*/
int openconnect_obtain_cookie(struct openconnect_info *vpninfo)
{
struct vpn_option *opt, *next;
struct vpn_option *opt;
char buf[MAX_BUF_LEN];
char *form_buf = NULL;
int result, buflen;
Expand Down Expand Up @@ -676,92 +774,11 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo)

if (result != 200 && vpninfo->redirect_url) {
redirect:
if (!strncmp(vpninfo->redirect_url, "https://", 8)) {
/* New host. Tear down the existing connection and make a new one */
char *host;
int port;
int ret;

free(vpninfo->urlpath);
vpninfo->urlpath = NULL;

ret = internal_parse_url(vpninfo->redirect_url, NULL, &host, &port, &vpninfo->urlpath, 0);
if (ret) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to parse redirected URL '%s': %s\n"),
vpninfo->redirect_url, strerror(-ret));
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
free(form_buf);
return ret;
}

if (strcasecmp(vpninfo->hostname, host) || port != vpninfo->port) {
free(vpninfo->hostname);
vpninfo->hostname = host;
vpninfo->port = port;

/* Kill the existing connection, and a new one will happen */
free(vpninfo->peer_addr);
vpninfo->peer_addr = NULL;
openconnect_close_https(vpninfo, 0);

for (opt = vpninfo->cookies; opt; opt = next) {
next = opt->next;

free(opt->option);
free(opt->value);
free(opt);
}
vpninfo->cookies = NULL;
} else
free(host);

free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;

result = handle_redirect(vpninfo);
if (result == 0)
goto retry;
} else if (strstr(vpninfo->redirect_url, "://")) {
vpn_progress(vpninfo, PRG_ERR,
_("Cannot follow redirection to non-https URL '%s'\n"),
vpninfo->redirect_url);
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
free(form_buf);
return -EINVAL;
} else if (vpninfo->redirect_url[0] == '/') {
/* Absolute redirect within same host */
free(vpninfo->urlpath);
vpninfo->urlpath = strdup(vpninfo->redirect_url + 1);
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
goto retry;
} else {
char *lastslash = NULL;
if (vpninfo->urlpath)
lastslash = strrchr(vpninfo->urlpath, '/');
if (!lastslash) {
free(vpninfo->urlpath);
vpninfo->urlpath = vpninfo->redirect_url;
vpninfo->redirect_url = NULL;
} else {
char *oldurl = vpninfo->urlpath;
*lastslash = 0;
vpninfo->urlpath = NULL;
if (asprintf(&vpninfo->urlpath, "%s/%s",
oldurl, vpninfo->redirect_url) == -1) {
int err = -errno;
vpn_progress(vpninfo, PRG_ERR,
_("Allocating new path for relative redirect failed: %s\n"),
strerror(-err));
return err;
}
free(oldurl);
free(vpninfo->redirect_url);
vpninfo->redirect_url = NULL;
}
goto retry;
}
free(form_buf);
return result;
}
if (!form_buf || result != 200) {
vpn_progress(vpninfo, PRG_ERR,
Expand Down

0 comments on commit 3edcc28

Please sign in to comment.