httpserver.c
上传用户:qin5330
上传日期:2007-01-05
资源大小:114k
文件大小:10k
源码类别:

搜索引擎

开发平台:

Perl

  1. /*
  2. ** Copyright (C) 1995, 1996, 1997, 1998 Hewlett-Packard Company
  3. ** Originally by Kevin Hughes, kev@kevcom.com, 3/11/94
  4. **
  5. ** This program and library is free software; you can redistribute it and/or
  6. ** modify it under the terms of the GNU (Library) General Public License
  7. ** as published by the Free Software Foundation; either version 2
  8. ** of the License, or any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU (Library) General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU (Library) General Public License
  16. **  long with this program; if not, write to the Free Software
  17. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18. **--------------------------------------------------------------------
  19. ** All the code in this file added by Ron Klachko ron@ckm.ucsf.edu 9/98
  20. ** 
  21. */
  22. /*
  23. ** httpserver.c
  24. */
  25. #ifndef _WIN32
  26. #include <unistd.h>
  27. #endif
  28. #include <time.h>
  29. #include <stdarg.h>
  30. #include "swish.h"
  31. #include "string.h"
  32. #include "mem.h"
  33. #include "http.h"
  34. #include "httpserver.h"
  35. /* The list of servers that we are acting on.
  36. **/
  37. static httpserverinfo *servers = 0;
  38. static void parserobotstxt(FILE *fp, httpserverinfo *server);
  39. static char *isolatevalue(char *line, char *keyword, int *plen);
  40. static int serverinlist(char *url, struct swline *list);
  41. /* Find the robot rules for this URL.  If haven't retrieved them
  42. ** yet, do so now.
  43. **/
  44. httpserverinfo *getserverinfo(char *url)
  45. {
  46.     httpserverinfo *server;
  47.     char *method;
  48.     int methodlen;
  49.     char *serverport;
  50.     int serverportlen;
  51.     char contenttype[MAXSTRLEN];
  52.     char buffer[MAXSTRLEN];
  53.     FILE *fp;
  54.     if ((method = url_method(url, &methodlen)) == 0) {
  55. return 0;
  56.     }
  57.     if ((serverport = url_serverport(url, &serverportlen)) == 0) {
  58. return 0;
  59.     }
  60.     /* Search for the rules
  61.     **/
  62.     for (server = servers; server; server = server->next) {
  63. if (equivalentserver(url, server->baseurl)) {
  64. return server;
  65. }
  66.     }
  67.     
  68.     /* Create a new entry for this server and add it to the list.
  69.     **/
  70.     server = (httpserverinfo *)emalloc(sizeof(httpserverinfo));
  71.     /* +3 for the ://, +1 for the trailing /, +1 for the terminating null
  72.     **/
  73.     server->baseurl = (char *)emalloc(methodlen + serverportlen + 5);
  74.     sprintf (server->baseurl, "%.*s://%.*s/", methodlen, method, serverportlen, serverport );
  75.     
  76.     server->lastretrieval = 0;
  77.     server->robotrules = 0;
  78.     server->next = servers;
  79.     servers = server;
  80.     /* Only http(s) servers can full rules, all the other ones just get dummies
  81.     ** (this is useful for holding last retrieval)
  82.     **
  83.     ** http://info.webcrawler.com/mak/projects/robots/norobots.html holds what
  84.     ** many people consider the official web exclusion rules.  Unfortunately,
  85.     ** the rules are not consistent about how records are formed.  One line
  86.     ** states "the file consists of one or more records separated by one or more
  87.     ** blank lines" while another states "the record starts with one or more User-agent
  88.     ** lines, followed by one or more Disallow lines."
  89.     **
  90.     ** So, does a blank line after a User-agent line end a record?  The spec is
  91.     ** unclear on this matter.  If the next legal line afer the blank line is
  92.     ** a Disallow line, the blank line should most likely be ignored.  But what
  93.     ** if the next line is another User-agent line?  For example:
  94.     **
  95.     ** User-agent: MooBot
  96.     **
  97.     ** User-agent: CreepySpider
  98.     ** Disallow: /cgi-bin
  99.     **
  100.     ** One interpretation (based on blank lines termination records) is that MooBot
  101.     ** may visit any location (since there are no Disallows for it).  Another
  102.     ** interpretation (based on records needing both User-agent and Disallow lines)
  103.     ** is that MooBot may not visit /cgi-bin
  104.     **
  105.     ** While poking around, I found at least one site (www.sun.com) that uses blank
  106.     ** lines within records.  Because of that, I have decided to rely on records
  107.     ** having both User-agent and Disallow lines (the second interpretation above).
  108.     **/
  109.     if (strncmp(server->baseurl, "http", 4) == 0) {
  110. sprintf(buffer, "%srobots.txt", server->baseurl);
  111. if (get(contenttype, &server->lastretrieval, buffer) == 200) {
  112. sprintf(buffer, "%s/swishspider@%ld.contents", tmpdir, lgetpid());
  113. fp = fopen(buffer, "r");
  114. parserobotstxt(fp, server);
  115. fclose(fp);
  116. }
  117. cmdf(unlink, "%s/swishspider@%ld.response", tmpdir, lgetpid());
  118. cmdf(unlink, "%s/swishspider@%ld.contents", tmpdir, lgetpid());
  119. cmdf(unlink, "%s/swishspider@%ld.links", tmpdir, lgetpid());
  120.     }
  121.     return server;
  122. }
  123. int urldisallowed(char *url)
  124. {
  125.     httpserverinfo *server;
  126.     robotrules *rule;
  127.     char *uri;
  128.     int urilen;
  129.     if ((server = getserverinfo(url)) == 0) {
  130. return 1;
  131.     }
  132.     if ((uri = url_uri(url, &urilen)) == 0) {
  133. return 1;
  134.     }
  135.     for (rule = server->robotrules; rule; rule = rule->next) {
  136. if (strncmp(uri, rule->disallow, strlen(rule->disallow)) == 0) {
  137. return 1;
  138. }
  139.     }
  140.     return 0;
  141. }
  142. static char useragent[] = "user-agent:";
  143. static char disallow[] = "disallow:";
  144. static char swishspider[] = "swishspider";
  145. static void parserobotstxt(FILE *fp, httpserverinfo *server)
  146. {
  147.     char buffer[MAXSTRLEN];
  148.     enum {START, USERAGENT, DISALLOW} state = START;
  149.     enum {SPECIFIC, GENERIC, SKIPPING} useragentstate = SKIPPING;
  150.     char *p;
  151.     int len;
  152.     robotrules *entry;
  153.     robotrules *entry2;
  154.     server->useragent = 0;
  155.     
  156.     while (fgets(buffer, sizeof buffer, fp) != 0) {
  157. /* Remove end of line indicators
  158. **/
  159. while ((*(buffer + strlen(buffer) - 1) == 'r') ||
  160. (*(buffer + strlen(buffer) - 1) == 'n')) {
  161. *(buffer + strlen(buffer) - 1) = '';
  162. }
  163. if ((*buffer == '#') || (*buffer == ''))
  164. continue;
  165. if (strncasecmp(buffer, useragent, sizeof(useragent) - 1) == 0) {
  166. switch (state) {
  167. case DISALLOW:
  168. /* Since we found our specific user-agent, we can
  169. ** skip the rest of the file.
  170. **/
  171. if (useragentstate == SPECIFIC) {
  172. return;
  173. }
  174. useragentstate = SKIPPING;
  175. /* explict fallthrough */
  176. case START:
  177. case USERAGENT:
  178. state = USERAGENT;
  179. if (useragentstate != SPECIFIC) {
  180. p = isolatevalue(buffer, useragent, &len);
  181. if ((len == (sizeof(swishspider) - 1)) &&
  182. (strncasecmp(p, swishspider, sizeof(swishspider) - 1) == 0) ) {
  183. useragentstate = SPECIFIC;
  184. /* We might have already parsed generic rules,
  185. ** so clean them up if necessary.
  186. */
  187. if (server->useragent) {
  188. free(server->useragent);
  189. }
  190. for (entry = server->robotrules; entry; ) {
  191. entry2 = entry->next;
  192. free(entry);
  193. entry = entry2;
  194. }
  195. server->robotrules = 0;
  196. server->useragent = (char *)emalloc(len + 1);
  197. strncpy(server->useragent, p, len);
  198. *(server->useragent + len) = '';
  199. }
  200. else if ((len == 1) && (*p == '*')) {
  201. useragentstate = GENERIC;
  202. server->useragent = (char *)emalloc(2);
  203. strcpy(server->useragent, "*");
  204. }
  205. }
  206. break;
  207. }
  208. }
  209. if (strncasecmp(buffer, disallow, sizeof(disallow) - 1) == 0) {
  210. state = DISALLOW;
  211. if (useragentstate != SKIPPING) {
  212. p = isolatevalue(buffer, disallow, &len);
  213. if (len) {
  214. entry = (robotrules *)emalloc(sizeof(robotrules));
  215. entry->next = server->robotrules;
  216. server->robotrules = entry;
  217. entry->disallow = (char *)emalloc(len + 1);
  218. strncpy(entry->disallow, p, len);
  219. *(entry->disallow + len) = '';
  220. }
  221. }
  222. }
  223.     }
  224. }
  225. static char *isolatevalue(char *line, char *keyword, int *plen)
  226. {
  227. /* Find the beginning of the value
  228.     **/
  229.     for (line += strlen(keyword); isspace(*line); line++ ) {
  230.     }
  231.     /* Strip off trailing spaces
  232.     **/
  233.     for (*plen = strlen(line); isspace(*(line + *plen - 1)); (*plen)--) {
  234.     }
  235.     return line;
  236. }
  237. int equivalentserver(char *url, char *baseurl)
  238. {
  239.     char *method;
  240.     int methodlen;
  241.     char *serverport;
  242.     int serverportlen;
  243.     char *basemethod;
  244.     int basemethodlen;
  245.     char *baseserverport;
  246.     int baseserverportlen;
  247.     multiswline *walk;
  248.     method = url_method(url, &methodlen);
  249.     serverport = url_serverport(url, &serverportlen);
  250.     basemethod = url_method(baseurl, &basemethodlen);
  251.     baseserverport = url_serverport(baseurl, &baseserverportlen);
  252.     if (!method || !serverport || !basemethod || !baseserverport) {
  253. return 0;
  254.     }
  255.     /* If this is the same server, we just go for it
  256.     **/
  257.     if ((methodlen == basemethodlen) && (serverportlen == baseserverportlen) &&
  258. (strncasecmp(method, basemethod, methodlen) == 0) &&
  259. (strncasecmp(serverport, baseserverport, serverportlen) == 0)) {
  260. return 1;
  261.     }
  262.     /* Do we find the method/server info for this and the base url
  263.     ** in the same equivalence list?
  264.     **/
  265.     for (walk = equivalentservers; walk; walk = walk->next ) {
  266. if (serverinlist(url, walk->list) &&
  267. serverinlist(baseurl, walk->list)) {
  268. return 1;
  269. }
  270.     }
  271.     return 0;
  272. }
  273. static int serverinlist(char *url, struct swline *list)
  274. {
  275.     char *method;
  276.     int methodlen;
  277.     char *serverport;
  278.     int serverportlen;
  279.     char *listmethod;
  280.     int listmethodlen;
  281.     char *listserverport;
  282.     int listserverportlen;
  283.     
  284.     method = url_method(url, &methodlen);
  285.     serverport = url_serverport(url, &serverportlen);
  286.     if (!method || !serverport) {
  287. return 0;
  288.     }
  289.     for ( ; list; list = list->next) {
  290. listmethod = url_method(list->line, &listmethodlen);
  291. listserverport = url_serverport(list->line, &listserverportlen);
  292. if (listmethod && listserverport) {
  293. if ((methodlen == listmethodlen) && (serverportlen == listserverportlen) &&
  294. (strncasecmp(method, listmethod, methodlen) == 0) &&
  295. (strncasecmp(serverport, listserverport, serverportlen) == 0)) {
  296. return 1;
  297. }
  298. }
  299.     }
  300.     return 0;
  301. }