📄 gopher.c
字号:
/* * $Id: gopher.c,v 1.150 1999/01/31 15:58:54 wessels Exp $ * * DEBUG: section 10 Gopher * AUTHOR: Harvest Derived * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from the * Internet community. Development is led by Duane Wessels of the * National Laboratory for Applied Network Research and funded by the * National Science Foundation. Squid is Copyrighted (C) 1998 by * Duane Wessels and the University of California San Diego. Please * see the COPYRIGHT file for full details. Squid incorporates * software developed and/or copyrighted by other sources. Please see * the CREDITS file for full details. * * 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. * * 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, USA. * */#include "squid.h"/* gopher type code from rfc. Anawat. */#define GOPHER_FILE '0'#define GOPHER_DIRECTORY '1'#define GOPHER_CSO '2'#define GOPHER_ERROR '3'#define GOPHER_MACBINHEX '4'#define GOPHER_DOSBIN '5'#define GOPHER_UUENCODED '6'#define GOPHER_INDEX '7'#define GOPHER_TELNET '8'#define GOPHER_BIN '9'#define GOPHER_REDUNT '+'#define GOPHER_3270 'T'#define GOPHER_GIF 'g'#define GOPHER_IMAGE 'I'#define GOPHER_HTML 'h' /* HTML */#define GOPHER_INFO 'i'#define GOPHER_WWW 'w' /* W3 address */#define GOPHER_SOUND 's'#define GOPHER_PLUS_IMAGE ':'#define GOPHER_PLUS_MOVIE ';'#define GOPHER_PLUS_SOUND '<'#define GOPHER_PORT 70#define TAB '\t'#define TEMP_BUF_SIZE 4096#define MAX_CSO_RESULT 1024typedef struct gopher_ds { StoreEntry *entry; char host[SQUIDHOSTNAMELEN + 1]; enum { NORMAL, HTML_DIR, HTML_INDEX_RESULT, HTML_CSO_RESULT, HTML_INDEX_PAGE, HTML_CSO_PAGE } conversion; int HTML_header_added; int port; char type_id; char request[MAX_URL]; int data_in; int cso_recno; int len; char *buf; /* pts to a 4k page */ int fd; FwdState *fwdState;} GopherStateData;static PF gopherStateFree;static void gopher_mime_content(MemBuf * mb, const char *name, const char *def);static void gopherMimeCreate(GopherStateData *);static int gopher_url_parser(const char *url, char *host, int *port, char *type_id, char *request);static void gopherEndHTML(GopherStateData *);static void gopherToHTML(GopherStateData *, char *inbuf, int len);static PF gopherTimeout;static PF gopherReadReply;static CWCB gopherSendComplete;static PF gopherSendRequest;static GopherStateData *CreateGopherStateData(void);static char def_gopher_bin[] = "www/unknown";static char def_gopher_text[] = "text/plain";static voidgopherStateFree(int fdnotused, void *data){ GopherStateData *gopherState = data; if (gopherState == NULL) return; if (gopherState->entry) { storeUnlockObject(gopherState->entry); } memFree(gopherState->buf, MEM_4K_BUF); gopherState->buf = NULL; cbdataFree(gopherState);}/* figure out content type from file extension */static voidgopher_mime_content(MemBuf * mb, const char *name, const char *def_ctype){ char *ctype = mimeGetContentType(name); char *cenc = mimeGetContentEncoding(name); if (cenc) memBufPrintf(mb, "Content-Encoding: %s\r\n", cenc); memBufPrintf(mb, "Content-Type: %s\r\n", ctype ? ctype : def_ctype);}/* create MIME Header for Gopher Data */static voidgopherMimeCreate(GopherStateData * gopherState){ MemBuf mb; memBufDefInit(&mb); memBufPrintf(&mb, "HTTP/1.0 200 OK Gatewaying\r\n" "Server: Squid/%s\r\n" "Date: %s\r\n" "MIME-version: 1.0\r\n", version_string, mkrfc1123(squid_curtime)); switch (gopherState->type_id) { case GOPHER_DIRECTORY: case GOPHER_INDEX: case GOPHER_HTML: case GOPHER_WWW: case GOPHER_CSO: memBufPrintf(&mb, "Content-Type: text/html\r\n"); break; case GOPHER_GIF: case GOPHER_IMAGE: case GOPHER_PLUS_IMAGE: memBufPrintf(&mb, "Content-Type: image/gif\r\n"); break; case GOPHER_SOUND: case GOPHER_PLUS_SOUND: memBufPrintf(&mb, "Content-Type: audio/basic\r\n"); break; case GOPHER_PLUS_MOVIE: memBufPrintf(&mb, "Content-Type: video/mpeg\r\n"); break; case GOPHER_MACBINHEX: case GOPHER_DOSBIN: case GOPHER_UUENCODED: case GOPHER_BIN: /* Rightnow We have no idea what it is. */ gopher_mime_content(&mb, gopherState->request, def_gopher_bin); break; case GOPHER_FILE: default: gopher_mime_content(&mb, gopherState->request, def_gopher_text); break; } memBufPrintf(&mb, "\r\n"); EBIT_CLR(gopherState->entry->flags, ENTRY_FWD_HDR_WAIT); storeAppend(gopherState->entry, mb.buf, mb.size); memBufClean(&mb);}/* Parse a gopher url into components. By Anawat. */static intgopher_url_parser(const char *url, char *host, int *port, char *type_id, char *request){ LOCAL_ARRAY(char, proto, MAX_URL); LOCAL_ARRAY(char, hostbuf, MAX_URL); int t; proto[0] = hostbuf[0] = '\0'; host[0] = request[0] = '\0'; (*port) = 0; (*type_id) = 0; t = sscanf(url,#if defined(__QNX__) "%[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]://%[^/]/%c%s",#else "%[a-zA-Z]://%[^/]/%c%s",#endif proto, hostbuf, type_id, request); if ((t < 2) || strcasecmp(proto, "gopher")) { return -1; } else if (t == 2) { (*type_id) = GOPHER_DIRECTORY; request[0] = '\0'; } else if (t == 3) { request[0] = '\0'; } else { /* convert %xx to char */ url_convert_hex(request, 0); } host[0] = '\0'; if (sscanf(hostbuf, "%[^:]:%d", host, port) < 2) (*port) = GOPHER_PORT; return 0;}intgopherCachable(const char *url){ GopherStateData *gopherState = NULL; int cachable = 1; /* use as temp data structure to parse gopher URL */ gopherState = CreateGopherStateData(); /* parse to see type */ gopher_url_parser(url, gopherState->host, &gopherState->port, &gopherState->type_id, gopherState->request); switch (gopherState->type_id) { case GOPHER_INDEX: case GOPHER_CSO: case GOPHER_TELNET: case GOPHER_3270: cachable = 0; break; default: cachable = 1; } gopherStateFree(-1, gopherState); return cachable;}static voidgopherEndHTML(GopherStateData * gopherState){ if (!gopherState->data_in) storeAppendPrintf(gopherState->entry, "<HTML><HEAD><TITLE>Server Return Nothing.</TITLE>\n" "</HEAD><BODY><HR><H1>Server Return Nothing.</H1></BODY></HTML>\n");}/* Convert Gopher to HTML *//* Borrow part of code from libwww2 came with Mosaic distribution */static voidgopherToHTML(GopherStateData * gopherState, char *inbuf, int len){ char *pos = inbuf; char *lpos = NULL; char *tline = NULL; LOCAL_ARRAY(char, line, TEMP_BUF_SIZE); LOCAL_ARRAY(char, tmpbuf, TEMP_BUF_SIZE); LOCAL_ARRAY(char, outbuf, TEMP_BUF_SIZE << 4); char *name = NULL; char *selector = NULL; char *host = NULL; char *port = NULL; char *escaped_selector = NULL; char *icon_url = NULL; char gtype; StoreEntry *entry = NULL; memset(outbuf, '\0', TEMP_BUF_SIZE << 4); memset(tmpbuf, '\0', TEMP_BUF_SIZE); memset(line, '\0', TEMP_BUF_SIZE); entry = gopherState->entry; if (gopherState->conversion == HTML_INDEX_PAGE) { storeAppendPrintf(entry, "<HTML><HEAD><TITLE>Gopher Index %s</TITLE></HEAD>\n" "<BODY><H1>%s<BR>Gopher Search</H1>\n" "<p>This is a searchable Gopher index. Use the search\n" "function of your browser to enter search terms.\n" "<ISINDEX></BODY></HTML>\n", storeUrl(entry), storeUrl(entry)); /* now let start sending stuff to client */ storeBufferFlush(entry); gopherState->data_in = 1; return; } if (gopherState->conversion == HTML_CSO_PAGE) { storeAppendPrintf(entry, "<HTML><HEAD><TITLE>CSO Search of %s</TITLE></HEAD>\n" "<BODY><H1>%s<BR>CSO Search</H1>\n" "<P>A CSO database usually contains a phonebook or\n" "directory. Use the search function of your browser to enter\n" "search terms.</P><ISINDEX></BODY></HTML>\n", storeUrl(entry), storeUrl(entry)); /* now let start sending stuff to client */ storeBufferFlush(entry); gopherState->data_in = 1; return; } inbuf[len] = '\0'; if (!gopherState->HTML_header_added) { if (gopherState->conversion == HTML_CSO_RESULT) strcat(outbuf, "<HTML><HEAD><TITLE>CSO Searchs Result</TITLE></HEAD>\n" "<BODY><H1>CSO Searchs Result</H1>\n<PRE>\n"); else strcat(outbuf, "<HTML><HEAD><TITLE>Gopher Menu</TITLE></HEAD>\n" "<BODY><H1>Gopher Menu</H1>\n<PRE>\n"); gopherState->HTML_header_added = 1; } while ((pos != NULL) && (pos < inbuf + len)) { if (gopherState->len != 0) { /* there is something left from last tx. */ xstrncpy(line, gopherState->buf, gopherState->len); lpos = (char *) memccpy(line + gopherState->len, inbuf, '\n', len); if (lpos) *lpos = '\0'; else { /* there is no complete line in inbuf */ /* copy it to temp buffer */ if (gopherState->len + len > TEMP_BUF_SIZE) { debug(10, 1) ("GopherHTML: Buffer overflow. Lost some data on URL: %s\n", storeUrl(entry)); len = TEMP_BUF_SIZE - gopherState->len; } xmemcpy(gopherState->buf + gopherState->len, inbuf, len); gopherState->len += len; return; } /* skip one line */ pos = (char *) memchr(pos, '\n', len); if (pos) pos++; /* we're done with the remain from last tx. */ gopherState->len = 0; *(gopherState->buf) = '\0'; } else { lpos = (char *) memccpy(line, pos, '\n', len - (pos - inbuf)); if (lpos) *lpos = '\0'; else { /* there is no complete line in inbuf */ /* copy it to temp buffer */ if ((len - (pos - inbuf)) > TEMP_BUF_SIZE) { debug(10, 1) ("GopherHTML: Buffer overflow. Lost some data on URL: %s\n", storeUrl(entry)); len = TEMP_BUF_SIZE; } if (len > (pos - inbuf)) { xmemcpy(gopherState->buf, pos, len - (pos - inbuf)); gopherState->len = len - (pos - inbuf); } break; } /* skip one line */ pos = (char *) memchr(pos, '\n', len); if (pos) pos++; } /* at this point. We should have one line in buffer to process */ if (*line == '.') { /* skip it */ memset(line, '\0', TEMP_BUF_SIZE); continue; } switch (gopherState->conversion) { case HTML_INDEX_RESULT: case HTML_DIR:{ tline = line; gtype = *tline++; name = tline; selector = strchr(tline, TAB); if (selector) { *selector++ = '\0'; host = strchr(selector, TAB); if (host) { *host++ = '\0'; port = strchr(host, TAB);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -