Skip to content

Commit

Permalink
Add support for cookie
Browse files Browse the repository at this point in the history
Signed-off-by: Jason <[email protected]>
  • Loading branch information
Jason23347 committed May 20, 2020
1 parent fcbfd19 commit f5bbc14
Show file tree
Hide file tree
Showing 5 changed files with 342 additions and 1 deletion.
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
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(char *dst, const cookie_t *cookielist, int num, int maxlen)
{
strlcpy(dst, "Cookie:", maxlen);
const cookie_t *cookie = cookielist;
// TODO simplify the code
for (int i = 0; i < num; i++) {
strlcat(dst, " ", maxlen);
strlcat(dst, cookie->name, maxlen);
strlcat(dst, "=", maxlen);
strlcat(dst, cookie->value, maxlen);
strlcat(dst, ";", maxlen);
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(char *dst, const cookie_t *cookielist, int num, int maxlen);

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 */
36 changes: 35 additions & 1 deletion src/text.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ main(int argc, char *argv[])
{
char fn[MAX_STRING];
int do_search = 0;
char *cookiefile = 0;
cookie_t *cookielist;
int cookie_count;
FILE *fd;
search_t *search;
conf_t conf[1];
axel_t *axel;
Expand All @@ -121,7 +125,7 @@ main(int argc, char *argv[])
j = -1;
while (1) {
int option = getopt_long(argc, argv,
"s:n:o:S::46NqvhVakcH:U:T:",
"s:n:o:S::46NqvhVakb:cH:U:T:",
axel_options, NULL);
if (option == -1)
break;
Expand Down Expand Up @@ -182,6 +186,13 @@ main(int argc, char *argv[])
case 'k':
conf->insecure = 1;
break;
case 'b':
if (!optarg) {
print_help();
goto free_conf;
}
cookiefile = optarg;
break;
case 'c':
conf->no_clobber = 1;
break;
Expand Down Expand Up @@ -231,6 +242,29 @@ main(int argc, char *argv[])
goto free_conf;
}

if (cookiefile) {
fd = fopen(cookiefile, "r");
if (!fd) {
fprintf(stderr, _("Error opening cookie file %s\n"), cookiefile);
goto free_conf;
}
cookielist = calloc(COOKIE_PREALLOCATE_NUM, sizeof(cookie_t));
if (!cookielist) {
fprintf(stderr, _("Out of memory\n"));
goto free_conf;
}
for (int i = 0; i < COOKIE_PREALLOCATE_NUM - 1; i++)
cookielist[i].next = &cookielist[i + 1];
cookie_count = cookielist_loadfile(cookielist, fd);
fclose(fd);

// FIXME length of add_header string may not be enough.
cookielist_header(conf->add_header[conf->add_header_count++],
cookielist, cookie_count, sizeof(conf->add_header[0]));
cookielist_free(cookielist, cookie_count);
free(cookielist);
}

if (conf->max_redirect < 0) {
print_help();
return 1;
Expand Down

0 comments on commit f5bbc14

Please sign in to comment.