/* $Id: http_req.c,v 1.6 2003/03/03 14:35:25 ossi Exp $ *
*
* puf 0.9 Copyright (C) 2000-2003 by Oswald Buddenhagen <puf@ossi.cjb.net>
* based on puf 0.1.x (C) 1999,2000 by Anders Gavare <gavare@hotmail.com>
*
* You may modify and distribute this code under the terms of the GPL.
* There is NO WARRANTY of any kind. See COPYING for details.
*
* http_req.c - compose and send http request message
*
*/
#include "puf.h"
static char *user_agent;
void
init_user_agent(void)
{
struct utsname un;
char http_agent[SHORTSTR];
uname(&un);
snprintf(http_agent, SHORTSTR, PACKAGE "/" VERSION " (%s %s; %s)",
un.sysname, un.release, un.machine);
if (!(user_agent = strdup(http_agent)))
die(2, "out of memory.");
}
/* base64 encode - this is stolen from gnu wget */
void
encode_auth(char *p, char *s, int len)
{
int i;
static char tbl[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
};
if (!s)
return;
for (i = 0; i < len; i += 3, s += 3) {
*p++ = tbl[s[0] >> 2];
*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
*p++ = tbl[s[2] & 0x3f];
}
/* Pad the result if necessary... */
if (i == len + 1)
*(p - 1) = '=';
else if (i == len + 2)
*(p - 1) = *(p - 2) = '=';
/* ...and zero-terminate it. */
*p = '\0';
}
/* Send http 'GET' command for a url: */
int
send_http_get(aurl_t *au)
{
char buf[MAXBUFSIZE], tmp[SHORTSTR], *topo, *agnt;
struct tm *a_tm;
int i, pos = 0;
u_int j;
/* char http_ver; */
/* oops: don't want to use this for now, as http/1.1 has too many rules.
http_ver = ((au->file_off || max_url_bytes) &&
au->url->host->info->is_http11) ? '1' : '0';
pos = sprintf(buf, "GET /%s HTTP/1.%c\r\nHost: %s:%i\r\n",
au->url->local_part, http_ver,
au->url->host->name, au->url->port); */
/* using "Range:" with http/1.0 request should not work according to the
http/1.1 spec (if i understood it correctly), but in practice it
DOES work with the most common servers (in most cases) ...
ok: apache, iis, webstar, netscape
bad: bestwww, enterpriseweb (did anybody hear about them? <g>) */
sprintf(tmp, au->url->port == 80 ? "%s" : "%s:%hi",
au->url->host->name, au->url->port);
if (au->proxy) {
prx(NFO, "requesting http://%s/%s via http://%s:%hi/%s\n",
tmp, au->url->local_part,
au->proxy->host->name, au->proxy->port, au->proxy->cgi_path);
pos = sprintf(buf, "GET http://%s/%s HTTP/1.0\r\nHost: %s\r\n",
tmp, au->url->local_part, tmp);
if (au->proxy->have_auth)
pos += sprintf(buf + pos, "Proxy-Authorization: Basic %s\r\n",
au->proxy->cgi_path + strlen(au->proxy->cgi_path) + 1);
} else {
prx(NFO, "requesting http://%s/%s\n", tmp, au->url->local_part);
pos = sprintf(buf, "GET /%s HTTP/1.0\r\nHost: %s\r\n",
au->url->local_part, tmp);
}
if (au->url->parm->opt->user_agents.nents) {
agent_t *ag;
i = RND(au->url->parm->opt->uar_total);
j = au->url->parm->opt->user_agents.nents;
do {
ag = ((agent_t **)au->url->parm->opt->user_agents.ents)[--j];
if ((i -= ag->ratio) < 0)
break;
} while (j > 0);
agnt = ag->agent;
} else
agnt = user_agent;
if (agnt[0])
pos += sprintf(buf + pos, "User-Agent: %s\r\n", agnt);
if (au->file_off && au->url->host->info->is_http11) {
/* oops: we cannot limit the file size, when the partial content
is outdated. however, this is caught elsewhere. it just causes
somewhat more traffic. */
pos += sprintf(buf + pos, au->url->parm->opt->max_bytes ?
"Range: bytes="SOFFT"-"SOFFT"\r\n" :
"Range: bytes="SOFFT"-\r\n",
au->file_off, au->url->parm->opt->max_bytes - 1);
topo = au->url->parm->opt->send_if_range ? "If-Range: %s\r\n" : 0;
} else {
if (au->url->parm->opt->max_bytes && au->url->host->info->is_http11)
pos += sprintf(buf + pos, "Range: bytes=0-"SOFFT"\r\n",
au->url->parm->opt->max_bytes - 1);
topo = au->file_time ? "If-Modified-Since: %s\r\n" : 0;
}
if (topo) {
a_tm = gmtime(&(au->file_time));
strftime(tmp, SHORTSTR, "%a, %d %b %Y %T GMT", a_tm);
pos += sprintf(buf + pos, topo, tmp);
}
if (au->url->parm->opt->send_referer && au->url->referer)
pos += sprintf(buf + pos, "Referer: http://%s/%s\r\n",
au->url->referer->host->name,
au->url->referer->local_part);
if (au->url->parm->http_auth)
pos +=
sprintf(buf + pos, "Authorization: Basic %s\r\n",
au->url->parm->http_auth);
for (j = 0; j < au->url->parm->opt->aux_headers.nents; j++)
pos += sprintf(buf + pos, "%s\r\n",
((char **)au->url->parm->opt->aux_headers.ents)[j]);
dbge(HDR, ("---request begin---\n%.*s---request end---\n", pos, buf));
pos += sprintf(buf + pos,
#ifdef HTTP_ACCEPT
HTTP_ACCEPT "\r\n"
#endif
"Connection: close\r\n\r\n");
return write(au->socket, buf, pos);
}
syntax highlighted by Code2HTML, v. 0.9.1