/* $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 * based on puf 0.1.x (C) 1999,2000 by Anders Gavare * * 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? ) */ 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); }