📄 gopher.c
字号:
if (port) { char *junk; port[0] = ':'; junk = strchr(host, TAB); if (junk) *junk++ = 0; /* Chop port */ else { junk = strchr(host, '\r'); if (junk) *junk++ = 0; /* Chop port */ else { junk = strchr(host, '\n'); if (junk) *junk++ = 0; /* Chop port */ } } if ((port[1] == '0') && (!port[2])) port[0] = 0; /* 0 means none */ } /* escape a selector here */ escaped_selector = xstrdup(rfc1738_escape(selector)); switch (gtype) { case GOPHER_DIRECTORY: icon_url = mimeGetIconURL("internal-menu"); break; case GOPHER_FILE: icon_url = mimeGetIconURL("internal-text"); break; case GOPHER_INDEX: case GOPHER_CSO: icon_url = mimeGetIconURL("internal-index"); break; case GOPHER_IMAGE: case GOPHER_GIF: case GOPHER_PLUS_IMAGE: icon_url = mimeGetIconURL("internal-image"); break; case GOPHER_SOUND: case GOPHER_PLUS_SOUND: icon_url = mimeGetIconURL("internal-sound"); break; case GOPHER_PLUS_MOVIE: icon_url = mimeGetIconURL("internal-movie"); break; case GOPHER_TELNET: case GOPHER_3270: icon_url = mimeGetIconURL("internal-telnet"); break; case GOPHER_BIN: case GOPHER_MACBINHEX: case GOPHER_DOSBIN: case GOPHER_UUENCODED: icon_url = mimeGetIconURL("internal-binary"); break; default: icon_url = mimeGetIconURL("internal-unknown"); break; } memset(tmpbuf, '\0', TEMP_BUF_SIZE); if ((gtype == GOPHER_TELNET) || (gtype == GOPHER_3270)) { if (strlen(escaped_selector) != 0) snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s@%s/\">%s</A>\n", icon_url, escaped_selector, host, name); else snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"telnet://%s/\">%s</A>\n", icon_url, host, name); } else { snprintf(tmpbuf, TEMP_BUF_SIZE, "<IMG BORDER=0 SRC=\"%s\"> <A HREF=\"gopher://%s/%c%s\">%s</A>\n", icon_url, host, gtype, escaped_selector, name); } safe_free(escaped_selector); strcat(outbuf, tmpbuf); gopherState->data_in = 1; } else { memset(line, '\0', TEMP_BUF_SIZE); continue; } } else { memset(line, '\0', TEMP_BUF_SIZE); continue; } break; } /* HTML_DIR, HTML_INDEX_RESULT */ case HTML_CSO_RESULT:{ int t; int code; int recno; LOCAL_ARRAY(char, result, MAX_CSO_RESULT); tline = line; if (tline[0] == '-') { t = sscanf(tline, "-%d:%d:%[^\n]", &code, &recno, result); if (t < 3) break; if (code != 200) break; if (gopherState->cso_recno != recno) { snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>Record# %d<br><i>%s</i></H2>\n<PRE>", recno, result); gopherState->cso_recno = recno; } else { snprintf(tmpbuf, TEMP_BUF_SIZE, "%s\n", result); } strcat(outbuf, tmpbuf); gopherState->data_in = 1; break; } else { /* handle some error codes */ t = sscanf(tline, "%d:%[^\n]", &code, result); if (t < 2) break; switch (code) { case 200:{ /* OK */ /* Do nothing here */ break; } case 102: /* Number of matches */ case 501: /* No Match */ case 502: /* Too Many Matches */ { /* Print the message the server returns */ snprintf(tmpbuf, TEMP_BUF_SIZE, "</PRE><HR><H2>%s</H2>\n<PRE>", result); strcat(outbuf, tmpbuf); gopherState->data_in = 1; break; } } } } /* HTML_CSO_RESULT */ default: break; /* do nothing */ } /* switch */ } /* while loop */ if ((int) strlen(outbuf) > 0) { storeAppend(entry, outbuf, strlen(outbuf)); /* now let start sending stuff to client */ storeBufferFlush(entry); } return;}static voidgopherTimeout(int fd, void *data){ GopherStateData *gopherState = data; StoreEntry *entry = gopherState->entry; debug(10, 4) ("gopherTimeout: FD %d: '%s'\n", fd, storeUrl(entry)); if (entry->store_status == STORE_PENDING) { if (entry->mem_obj->inmem_hi == 0) { fwdFail(gopherState->fwdState, errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT)); } } comm_close(fd);}/* This will be called when data is ready to be read from fd. Read until * error or connection closed. */static voidgopherReadReply(int fd, void *data){ GopherStateData *gopherState = data; StoreEntry *entry = gopherState->entry; char *buf = NULL; int len; int clen; int bin; size_t read_sz;#if DELAY_POOLS delay_id delay_id = delayMostBytesAllowed(entry->mem_obj);#endif if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { comm_close(fd); return; } errno = 0; buf = memAllocate(MEM_4K_BUF); read_sz = 4096 - 1; /* leave room for termination */#if DELAY_POOLS read_sz = delayBytesWanted(delay_id, 1, read_sz);#endif /* leave one space for \0 in gopherToHTML */ Counter.syscalls.sock.reads++; len = read(fd, buf, read_sz); if (len > 0) { fd_bytes(fd, len, FD_READ);#if DELAY_POOLS delayBytesIn(delay_id, len);#endif kb_incr(&Counter.server.all.kbytes_in, len); kb_incr(&Counter.server.other.kbytes_in, len); } debug(10, 5) ("gopherReadReply: FD %d read len=%d\n", fd, len); if (len > 0) { commSetTimeout(fd, Config.Timeout.read, NULL, NULL); IOStats.Gopher.reads++; for (clen = len - 1, bin = 0; clen; bin++) clen >>= 1; IOStats.Gopher.read_hist[bin]++; } if (len < 0) { debug(50, 1) ("gopherReadReply: error reading: %s\n", xstrerror()); if (ignoreErrno(errno)) { commSetSelect(fd, COMM_SELECT_READ, gopherReadReply, data, 0); } else if (entry->mem_obj->inmem_hi == 0) { ErrorState *err; err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR); err->xerrno = errno; err->url = xstrdup(storeUrl(entry)); errorAppendEntry(entry, err); comm_close(fd); } else { comm_close(fd); } } else if (len == 0 && entry->mem_obj->inmem_hi == 0) { ErrorState *err; err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE); err->xerrno = errno; err->url = xstrdup(gopherState->request); errorAppendEntry(entry, err); comm_close(fd); } else if (len == 0) { /* Connection closed; retrieval done. */ /* flush the rest of data in temp buf if there is one. */ if (gopherState->conversion != NORMAL) gopherEndHTML(data); storeTimestampsSet(entry); storeBufferFlush(entry); fwdComplete(gopherState->fwdState); comm_close(fd); } else { if (gopherState->conversion != NORMAL) { gopherToHTML(data, buf, len); } else { storeAppend(entry, buf, len); } commSetSelect(fd, COMM_SELECT_READ, gopherReadReply, data, 0); } memFree(buf, MEM_4K_BUF); return;}/* This will be called when request write is complete. Schedule read of * reply. */static voidgopherSendComplete(int fd, char *buf, size_t size, int errflag, void *data){ GopherStateData *gopherState = (GopherStateData *) data; StoreEntry *entry = gopherState->entry; debug(10, 5) ("gopherSendComplete: FD %d size: %d errflag: %d\n", fd, size, errflag); if (size > 0) { fd_bytes(fd, size, FD_WRITE); kb_incr(&Counter.server.all.kbytes_out, size); kb_incr(&Counter.server.other.kbytes_out, size); } if (errflag) { ErrorState *err; err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE); err->xerrno = errno; err->host = xstrdup(gopherState->host); err->port = gopherState->port; err->url = xstrdup(storeUrl(entry)); errorAppendEntry(entry, err); comm_close(fd); if (buf) memFree(buf, MEM_4K_BUF); /* Allocated by gopherSendRequest. */ return; } /* * OK. We successfully reach remote site. Start MIME typing * stuff. Do it anyway even though request is not HTML type. */ gopherMimeCreate(gopherState); switch (gopherState->type_id) { case GOPHER_DIRECTORY: /* we got to convert it first */ storeBuffer(entry); gopherState->conversion = HTML_DIR; gopherState->HTML_header_added = 0; break; case GOPHER_INDEX: /* we got to convert it first */ storeBuffer(entry); gopherState->conversion = HTML_INDEX_RESULT; gopherState->HTML_header_added = 0; break; case GOPHER_CSO: /* we got to convert it first */ storeBuffer(entry); gopherState->conversion = HTML_CSO_RESULT; gopherState->cso_recno = 0; gopherState->HTML_header_added = 0; break; default: gopherState->conversion = NORMAL; } /* Schedule read reply. */ commSetSelect(fd, COMM_SELECT_READ, gopherReadReply, gopherState, 0); commSetDefer(fd, fwdCheckDeferRead, entry); if (buf) memFree(buf, MEM_4K_BUF); /* Allocated by gopherSendRequest. */}/* This will be called when connect completes. Write request. */static voidgopherSendRequest(int fd, void *data){ GopherStateData *gopherState = data; LOCAL_ARRAY(char, query, MAX_URL); char *buf = memAllocate(MEM_4K_BUF); char *t; if (gopherState->type_id == GOPHER_CSO) { sscanf(gopherState->request, "?%s", query); snprintf(buf, 4096, "query %s\r\nquit\r\n", query); } else if (gopherState->type_id == GOPHER_INDEX) { if ((t = strchr(gopherState->request, '?'))) *t = '\t'; snprintf(buf, 4096, "%s\r\n", gopherState->request); } else { snprintf(buf, 4096, "%s\r\n", gopherState->request); } debug(10, 5) ("gopherSendRequest: FD %d\n", fd); comm_write(fd, buf, strlen(buf), gopherSendComplete, data, memFree4K); if (EBIT_TEST(gopherState->entry->flags, ENTRY_CACHABLE)) storeSetPublicKey(gopherState->entry); /* Make it public */}voidgopherStart(FwdState * fwdState){ int fd = fwdState->server_fd; StoreEntry *entry = fwdState->entry; GopherStateData *gopherState = CreateGopherStateData(); storeLockObject(entry); gopherState->entry = entry; debug(10, 3) ("gopherStart: %s\n", storeUrl(entry)); Counter.server.all.requests++; Counter.server.other.requests++; /* Parse url. */ if (gopher_url_parser(storeUrl(entry), gopherState->host, &gopherState->port, &gopherState->type_id, gopherState->request)) { ErrorState *err; err = errorCon(ERR_INVALID_URL, HTTP_BAD_REQUEST); err->url = xstrdup(storeUrl(entry)); errorAppendEntry(entry, err); gopherStateFree(-1, gopherState); return; } comm_add_close_handler(fd, gopherStateFree, gopherState); if (((gopherState->type_id == GOPHER_INDEX) || (gopherState->type_id == GOPHER_CSO)) && (strchr(gopherState->request, '?') == NULL)) { /* Index URL without query word */ /* We have to generate search page back to client. No need for connection */ gopherMimeCreate(gopherState); if (gopherState->type_id == GOPHER_INDEX) { gopherState->conversion = HTML_INDEX_PAGE; } else { if (gopherState->type_id == GOPHER_CSO) { gopherState->conversion = HTML_CSO_PAGE; } else { gopherState->conversion = HTML_INDEX_PAGE; } } gopherToHTML(gopherState, (char *) NULL, 0); fwdComplete(fwdState); comm_close(fd); return; } gopherState->fd = fd; gopherState->fwdState = fwdState; commSetSelect(fd, COMM_SELECT_WRITE, gopherSendRequest, gopherState, 0); commSetTimeout(fd, Config.Timeout.read, gopherTimeout, gopherState);}static GopherStateData *CreateGopherStateData(void){ GopherStateData *gd = xcalloc(1, sizeof(GopherStateData)); cbdataAdd(gd, cbdataXfree, 0); gd->buf = memAllocate(MEM_4K_BUF); return (gd);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -