Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for cookie #304

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ axel_SOURCES = \
src/conf.h \
src/conn.c \
src/conn.h \
src/cookie.c \
src/cookie.h \
src/ftp.c \
src/ftp.h \
src/http.c \
Expand Down
1 change: 1 addition & 0 deletions src/axel.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ typedef message_t if_t;
#include "conf.h"
#include "tcp.h"
#include "ftp.h"
#include "cookie.h"
#include "http.h"
#include "conn.h"
#include "ssl.h"
Expand Down
12 changes: 10 additions & 2 deletions src/conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ conf_loadfile(conf_t *conf, const char *file)
_("Requested too many connections, max is %i\n"),
USHRT_MAX);
} else if (!strcmp(key, "user_agent")) {
conf_hdr_make(conf->add_header[HDR_USER_AGENT],
conf_hdr_make(&conf->add_header[HDR_USER_AGENT],
"User-Agent", DEFAULT_USER_AGENT);
continue;
}
Expand Down Expand Up @@ -242,7 +242,11 @@ conf_init(conf_t *conf)

conf->ai_family = AF_UNSPEC;

conf_hdr_make(conf->add_header[HDR_USER_AGENT],
for (i = 0; i < MAX_ADD_HEADERS; i++) {
abuf_setup(&conf->add_header[i], 1024);
}

conf_hdr_make(&conf->add_header[HDR_USER_AGENT],
"User-Agent", DEFAULT_USER_AGENT);
conf->add_header_count = HDR_count_init;

Expand Down Expand Up @@ -290,6 +294,10 @@ void
conf_free(conf_t *conf)
{
free(conf->interfaces);

for (int i = 0; i < MAX_ADD_HEADERS; i++) {
abuf_setup(&conf->add_header[i], ABUF_FREE);
}
}

int
Expand Down
6 changes: 3 additions & 3 deletions src/conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ typedef struct {
unsigned io_timeout;

int add_header_count;
char add_header[MAX_ADD_HEADERS][MAX_STRING];
abuf_t add_header[MAX_ADD_HEADERS];
} conf_t;

int conf_loadfile(conf_t *conf, const char *file);
Expand All @@ -84,9 +84,9 @@ enum {
};

inline static void
conf_hdr_make(char *dst, const char *k, const char *v)
conf_hdr_make(abuf_t *abuf, const char *k, const char *v)
{
snprintf(dst, sizeof(((conf_t *)0)->add_header[0]), "%s: %s", k, v);
abuf_printf(abuf, "%s: %s", k, v);
}

#endif /* AXEL_CONF_H */
2 changes: 1 addition & 1 deletion src/conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ conn_setup(conn_t *conn)
http_get(conn->http, s);
for (i = 0; i < conn->conf->add_header_count; i++)
http_addheader(conn->http, "%s",
conn->conf->add_header[i]);
conn->conf->add_header[i].p);
}
return 1;
}
Expand Down
241 changes: 241 additions & 0 deletions src/cookie.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/*
Axel -- A lighter download accelerator for Linux and other Unices

Copyright 2020 Jason

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

In addition, as a special exception, the copyright holders give
permission to link the code of portions of this program with the
OpenSSL library under certain conditions as described in each
individual source file, and distribute linked combinations including
the two.

You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the
file(s), but you are not obligated to do so. If you do not wish to do
so, delete this exception statement from your version. If you delete
this exception statement from all source files in the program, then
also delete it here.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "config.h"

#include "axel.h"

/**
* Load cookies from netscape HTTP cookie file.
* https://curl.haxx.se/docs/http-cookies.html.
*
* @returns number of cookies.
*/
int
cookielist_loadfile(cookie_t *cookielist, FILE *fd)
{
abuf_t *abuf;
cookie_t *cookie = cookielist;
size_t len, l;
int count = 0;

abuf = calloc(1, sizeof(abuf_t));
if (!abuf) {
fprintf(stderr, _("Out of memory\n"));
return 0;
}

if (abuf_setup(abuf, 1024) < 0) {
fprintf(stderr, _("Out of memory\n"));
goto nomem;
}

for (cookie_t *tmp = cookie; fgets(abuf->p, abuf->len, fd);) {
len = strlen(abuf->p);
if (len == abuf->len - 1) {
for (;;) {
if (abuf->len > MAX_COOKIE) {
printf(_("Unsupported cookie (Too long)\n"));
goto unsupported;
}
/* Realocate abuf */
if(abuf_setup(abuf, abuf->len + COOKIE_CHUNK) < 0) {
fprintf(stderr, _("Out of memory\n"));
goto nomem;
}
/* Read more bytes, break when line ends */
if (!fgets(abuf->p + len, COOKIE_CHUNK, fd))
break;
l = strlen(abuf->p + len);
len += l;
if (l < COOKIE_CHUNK - 1) {
/* Resize abuf, this shall not fail */
abuf_setup(abuf, len);
break;
}
}
}

/* Ignore lines empty or start with "# " */
if (abuf->p[0] == '\n' || (abuf->p[0] == '#' && abuf->p[1] == ' '))
continue;

/* Check if preallocated memory is used up */
if (!cookie) {
cookie = calloc(1, sizeof(cookie_t));
if (!cookie) {
fprintf(stderr, _("Out of memory\n"));
goto nomem;
}
tmp->next = cookie;
}
/* Store values into cookie, ignore broken one */
#ifndef NDEBUG
printf("Loading cookie line: %s\n", abuf->p);
#endif
if (cookie_load(cookie, abuf) < 0)
continue;

tmp = cookie;
cookie = tmp->next;

count++;
}

unsupported:
nomem:
abuf_setup(abuf, ABUF_FREE);
free(abuf);

return count;
}

void
cookielist_header(abuf_t *abuf, const cookie_t *cookielist, int num)
{
strlcpy(abuf->p, "Cookie:", abuf->len);
const cookie_t *cookie = cookielist;
// TODO simplify the code
for (int i = 0; i < num; i++) {
abuf_strcat(abuf, " ");
abuf_strcat(abuf, cookie->name);
abuf_strcat(abuf, "=");
abuf_strcat(abuf, cookie->value);
abuf_strcat(abuf, ";");
cookie = cookie->next;
}
}

inline void
cookie_free(cookie_t *cookie)
{
free_if_exists(cookie->name);
free_if_exists(cookie->value);
}

/* Free a cookie list. */
void
cookielist_free(cookie_t *cookielist, int num)
{
cookie_t *tmp, *cur;
tmp = cur = cookielist[COOKIE_PREALLOCATE_NUM - 1].next;

num -= COOKIE_PREALLOCATE_NUM;
if (num > 0) {
for (int i = 0; i < num; i++) {
tmp = tmp->next;
cookie_free(cur);
free(cur);
cur = tmp;
}
}

for (cur = cookielist;
cur - cookielist < COOKIE_PREALLOCATE_NUM;
cur++) {
cookie_free(cur);
}
}

int
cookie_strcpy(char *dst, const char *src, const char *space)
{
int i;
const char *s, *p;

s = p = src;
p = strpbrk(p, space);
if (!p)
return -1;
i = p - s;
dst = realloc(dst, i);
if (!dst) {
fprintf(stderr, _("Out of memory\n"));
return -1;
}
memcpy(dst, s, i);
dst[i] = 0;

return 0;
}

int
cookie_setup(cookie_t *cookie)
{
cookie->name = realloc(cookie->name, 0);
if (!cookie->name)
return -ENOMEM;
cookie->value = realloc(cookie->value, 0);
if (!cookie->value)
return -ENOMEM;

return 0;
}

/**
* Load cookie from abuf
* @returns 0 if OK, negative value on error.
*/
int
cookie_load(cookie_t *cookie, const abuf_t *abuf)
{
const char space[] = " \t\n";
char *s, *p;
int i;

/* Skipping unsupported fields */
s = p = abuf->p;
for (i = 0; (p = strpbrk(p, space)) && i < 5; i++, p = s) {
s = p + strspn(p, space);
if (!*s) {
fprintf(stderr, _("Invalid cookie\n"));
return -1;
}
*p = 0;
}

cookie_setup(cookie);

/* Name field */
if (cookie_strcpy(cookie->name, s, space) < 0)
return -1;

p = strpbrk(s, space);
s = p + strspn(p, space);
/* Value field */
if (cookie_strcpy(cookie->value, s, space) < 0)
return -1;

return 0;
}
63 changes: 63 additions & 0 deletions src/cookie.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
Axel -- A lighter download accelerator for Linux and other Unices

Copyright 2020 Jason

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

In addition, as a special exception, the copyright holders give
permission to link the code of portions of this program with the
OpenSSL library under certain conditions as described in each
individual source file, and distribute linked combinations including
the two.

You must obey the GNU General Public License in all respects for all
of the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the
file(s), but you are not obligated to do so. If you do not wish to do
so, delete this exception statement from your version. If you delete
this exception statement from all source files in the program, then
also delete it here.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
*/

#ifndef AXEL_COOKIE_H
#define AXEL_COOKIE_H

/* At least 4096 bytes per cookie according to RFC6265 section 6.1 */
#define MAX_COOKIE 4096

#define COOKIE_CHUNK 512

#define COOKIE_PREALLOCATE_NUM 10

/* Basic support for cookies */
typedef struct {
char *name;
char *value;
void *next;
} cookie_t;

#define free_if_exists(variable) { if (variable) free(variable); }

void cookielist_free(cookie_t *cookielist, int num);
int cookielist_loadfile(cookie_t *cookielist, FILE *fd);
void cookielist_header(abuf_t *abuf, const cookie_t *cookielist, int num);

int cookie_setup(cookie_t *cookie);
int cookie_strcpy(char *str, const char *dst, const char *space);
int cookie_load(cookie_t *cookie, const abuf_t *abuf);

#endif /* AXEL_COOKIE_H */
Loading