📄 http.c
字号:
/* $Id: http.C,v 1.5 2003/01/02 22:07:05 jastr Exp $ *//* * * Copyright (C) 2000 David Mazieres (dm@uun.org) * * 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, or (at * your option) any later version. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * *//*cause strptime to be defined on planetlab*/#if defined(__linux) && !defined(_GNU_SOURCE) # define _GNU_SOURCE#endif#include "http.h"#include "rxx.h"#include "sha1.h"#include <pwd.h>#include <time.h>static rxx hdrnameval ("^([^\\s:]+):\\s*(.*)\r?\n\\z", "s");strsuio_remstr (suio *uio, size_t n){ mstr m (n); uio->copyout (m, n); uio->rembytes (n); return m;}strhashstr (str src){ char hash[sha1::hashsize]; sha1_hash (hash, src, src.len ()); return armor32 (hash, sizeof (hash));}strhttptime (){ char buf[30]; time_t now = time (NULL); int n = strftime (buf, 30, "%a, %d %b %Y %H:%M:%S GMT", gmtime (&now)); assert (n == 29); return buf;}strhttperror (int status, str statmsg, str url, str description){ static str server; if (!server) { struct passwd *pw = NULL; if (char *login = getlogin ()) pw = getpwnam (login); if (!pw) pw = getpwuid (getuid ()); if (pw && *pw->pw_gecos) server = strbuf ("%s's proxy server", pw->pw_gecos); else server = "G22.3033-010 proxy server"; } strbuf body; body << "<HTML><HEAD>\n\<TITLE>ERROR: The requested URL could not be retrieved</TITLE>\n\</HEAD><BODY>\n\<H1>ERROR</H1>\n\<H2>The requested URL could not be retrieved</H2>\n\<HR>\n\<P>\n\While trying to retrieve the URL:\n" << "<A HREF=\"" << url << "\">" << url << "</A>\n\<P>\n\The following error was encountered:\n\<P>\n" << "<STRONG>" << description << "</STRONG><BR>\n" << "<P>" << server << " at " << myname () << "\n" << "</BODY></HTML>\n"; strbuf head ("HTTP/1.0 %03d ", status); head << statmsg << "\r\n"; str now = httptime (); head << "Mime-Version: 1.0\r\nContent-Type: text/html\r\n" << "Content-Length: " << body.tosuio ()->resid () << "\r\n" << "Server: " << server << "\r\n" << "Date: " << now << "\r\n" << "Expires: " << now << "\r\n\r\n"; head.tosuio ()->take (body.tosuio ()); return head;}strhttpparse::gethdr (suio *uio){ size_t n = 0; for (const iovec *v = uio->iov (), *e = uio->iovlim (); v < e; n += v++->iov_len) { const char *base = static_cast<char *> (v->iov_base); const char *lim = base + v->iov_len; const char *p = base; while ((p = static_cast<char *> (memchr (p, '\n', v->iov_len)))) { p++; if (n + (p - base) == 1) { uio->rembytes (1); return ""; } if (n + (p - base) == 2 && *static_cast<char *> (uio->iov ()->iov_base) == '\r') { uio->rembytes (2); return ""; } if (p < lim) { if (*p == ' ' || *p == '\t') continue; } else if (v + 1 < e) { if (*static_cast<char *> (v[1].iov_base) == ' ' || *static_cast<char *> (v[1].iov_base) == '\t') continue; } else /* Might or might not have complete line, need next char to tell. */ return NULL; return suio_remstr (uio, n + (p - base)); } } return NULL;}strhttpparse::hdrname (str hdr){ if (!hdrnameval.search (hdr)) return NULL; return str2lower (hdrnameval[1]);}strhttpparse::hdrval (str hdr){ if (!hdrnameval.search (hdr)) panic << "hdrval: bad header: " << hdr << "\n"; return hdrnameval[2];}time_thttpparse::parsetime (const char *text){ time_t t; struct tm stm; bzero (&stm, sizeof (stm)); if (!strptime (text, "%a, %d %b %Y %H:%M:%S GMT", &stm) && !strptime (text, "%a %b %d %H:%M:%S %Y", &stm)) return -1; t = mktime (&stm); t += stm.tm_gmtoff; return t;}boolhttpparse::checkpragma (str val, str pragma){ strbuf rxb; rxb << "(^|,)\\s*"; for (const char *p = pragma, *e = p + pragma.len (); p < e; p++) if (isalnum (*p)) rxb.tosuio ()->print (p, 1); else { rxb.tosuio ()->print ("\\", 1); rxb.tosuio ()->print (p, 1); } rxb << "\\s*(,|$)"; str s (rxb); rxx pragmarx (s, "i"); return pragmarx.search (val);}static rxx urlrx ("^http://([\\w.-]+)(:(\\d+))?(/\\S*)?", "i");boolhttpparse::parseurl (str *host, u_int16_t *port, str *path, str url){ if (!urlrx.search (url)) return false; *host = str2lower (urlrx[1]); *port = 80; if (str p = urlrx[3]) convertint (p, port); if (!(*path = urlrx[4])) *path = "/"; return true;}extern char hostname[1024];extern int hostport;static rxx reqrx ("^(\\S+)\\s+(/\\S*)", "i");boolhttpparse::parsereq (str *method, str *url, str line){ if (!reqrx.search (line)) return false; *method = str2upper (reqrx[1]); if (hostport == 80) *url = strbuf () << "http://" << hostname << reqrx[2]; else *url = strbuf () << "http://" << hostname << ":" << hostport << reqrx[2]; return true;}static rxx resprx ("^HTTP/\\d+\\.\\d+\\s+([1-5]\\d\\d)\\s+(.*)", "i");boolhttpparse::parseresp (int *status, str *msg, str line){ if (!resprx.search (line)) return false; convertint (resprx[1], status); *msg = resprx[2]; return true;}inthttpparse::parse (suio *uio){ while (str h = gethdr (uio)) { if (!firstdone) { if (!dofirst (h)) return -1; firstdone = true; continue; } if (!h.len ()) return 1; if (!hdrnameval.search (h)) return -1; if (!doheader (str2lower (hdrnameval[1]), hdrnameval[2])) headers << h; } return 0;}boolhttpreq::dofirst (str line){ if (!parsereq (&method, &url, line) || !parseurl (&host, &port, &path, url)) return false; headers << method << " " << path << " HTTP/1.0\r\n"; urlhash = hashstr (url); return true;}boolhttpreq::doheader (str name, str val){ if (name == "pragma") { if (checkpragma (val, "no-cache")) nocache = true; } else if (name == "if-modified-since") { if_modified_since = parsetime (val); } else if (name == "content-length") content_length = atoi (val.cstr ()); // convertint (val, &content_length); else if (name == "authorization") authorization = val; else if (name == "referer") parseurl(&referer_host, &r_port, &r_path, val); return false;}boolhttpresp::dofirst (str line){ if (!parseresp (&status, &statusmsg, line)) return false; headers << line; return true;}boolhttpresp::doheader (str name, str val){ if (name == "pragma") { if (checkpragma (val, "no-cache")) nocache = true; } else if (name == "date") date = parsetime (val); else if (name == "expires") expires = parsetime (val); else if (name == "last-modified") last_modified = parsetime (val); else if (name == "content-length") content_length = atoi (val.cstr ()); return false;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -