#include "MemObject.h"
#endif
-/**
- \defgroup ServerProtocolGopherInternal Server-Side Gopher Internals
- \ingroup ServerProtocolGopherAPI
- * Gopher is somewhat complex and gross because it must convert from
- * the Gopher protocol to HTTP.
- */
-
/* gopher type code from rfc. Anawat. */
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_FILE '0'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_DIRECTORY '1'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_CSO '2'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_ERROR '3'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_MACBINHEX '4'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_DOSBIN '5'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_UUENCODED '6'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_INDEX '7'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_TELNET '8'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_BIN '9'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_REDUNT '+'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_3270 'T'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_GIF 'g'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_IMAGE 'I'
-/// \ingroup ServerProtocolGopherInternal
-#define GOPHER_HTML 'h' /* HTML */
-/// \ingroup ServerProtocolGopherInternal
+#define GOPHER_HTML 'h'
#define GOPHER_INFO 'i'
-/**
- \ingroup ServerProtocolGopherInternal
- W3 address
- */
+
+/// W3 address
#define GOPHER_WWW 'w'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_SOUND 's'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_PLUS_IMAGE ':'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_PLUS_MOVIE ';'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_PLUS_SOUND '<'
-/// \ingroup ServerProtocolGopherInternal
#define GOPHER_PORT 70
-/// \ingroup ServerProtocolGopherInternal
#define TAB '\t'
-/// \ingroup ServerProtocolGopherInternal
-/// \todo CODE: should this be a protocol-specific thing?
+
+// TODO CODE: should this be a protocol-specific thing?
#define TEMP_BUF_SIZE 4096
-/// \ingroup ServerProtocolGopherInternal
+
#define MAX_CSO_RESULT 1024
-/// \ingroup ServerProtocolGopherInternal
-typedef struct gopher_ds {
+/**
+ * Gopher Gateway Internals
+ *
+ * Gopher is somewhat complex and gross because it must convert from
+ * the Gopher protocol to HTTP.
+ */
+class GopherStateData
+{
+public:
+ GopherStateData(FwdState *aFwd) :
+ entry(aFwd->entry),
+ conversion(NORMAL),
+ HTML_header_added(0),
+ HTML_pre(0),
+ type_id(GOPHER_FILE /* '0' */),
+ cso_recno(0),
+ len(0),
+ buf(NULL),
+ fwd(aFwd)
+ {
+ *request = 0;
+ buf = (char *)memAllocate(MEM_4K_BUF);
+ entry->lock("gopherState");
+ *replybuf = 0;
+ }
+
+ /* AsyncJob API emulated */
+ void deleteThis(const char *aReason);
+ void swanSong();
+
+public:
StoreEntry *entry;
enum {
NORMAL,
int len;
char *buf; /* pts to a 4k page */
Comm::ConnectionPointer serverConn;
- HttpRequest *req;
FwdState::Pointer fwd;
char replybuf[BUFSIZ];
-} GopherStateData;
+
+private:
+ CBDATA_CLASS2(GopherStateData);
+};
+
+CBDATA_CLASS_INIT(GopherStateData);
static CLCB gopherStateFree;
static void gopherMimeCreate(GopherStateData *);
static IOCB gopherSendComplete;
static PF gopherSendRequest;
-/// \ingroup ServerProtocolGopherInternal
static char def_gopher_bin[] = "www/unknown";
-/// \ingroup ServerProtocolGopherInternal
static char def_gopher_text[] = "text/plain";
-/// \ingroup ServerProtocolGopherInternal
static void
gopherStateFree(const CommCloseCbParams ¶ms)
{
if (gopherState == NULL)
return;
- if (gopherState->entry) {
- gopherState->entry->unlock("gopherState");
- }
+ gopherState->deleteThis("gopherStateFree");
+}
- HTTPMSGUNLOCK(gopherState->req);
+void
+GopherStateData::deleteThis(const char *reason)
+{
+ swanSong();
+ delete this;
+}
- gopherState->fwd = NULL; // refcounted
+void
+GopherStateData::swanSong()
+{
+ if (entry)
+ entry->unlock("gopherState");
- memFree(gopherState->buf, MEM_4K_BUF);
- gopherState->buf = NULL;
- cbdataFree(gopherState);
+ if (buf)
+ memFree(buf, MEM_4K_BUF);
}
/**
- \ingroup ServerProtocolGopherInternal
* Create MIME Header for Gopher Data
*/
static void
}
/**
- \ingroup ServerProtocolGopherInternal
* Parse a gopher request into components. By Anawat.
*/
static void
}
/**
- \ingroup ServerProtocolGopherAPI
* Parse the request to determine whether it is cachable.
*
- \param req Request data.
- \retval 0 Not cachable.
- \retval 1 Cachable.
+ * \param req Request data.
+ * \retval 0 Not cachable.
+ * \retval 1 Cachable.
*/
int
gopherCachable(const HttpRequest * req)
return cachable;
}
-/// \ingroup ServerProtocolGopherInternal
static void
gopherHTMLHeader(StoreEntry * e, const char *title, const char *substring)
{
storeAppendPrintf(e, "</H1>\n");
}
-/// \ingroup ServerProtocolGopherInternal
static void
gopherHTMLFooter(StoreEntry * e)
{
storeAppendPrintf(e, "</ADDRESS></BODY></HTML>\n");
}
-/// \ingroup ServerProtocolGopherInternal
static void
gopherEndHTML(GopherStateData * gopherState)
{
}
/**
- \ingroup ServerProtocolGopherInternal
* Convert Gopher to HTML.
- \par
+ *
* Borrow part of code from libwww2 came with Mosaic distribution.
*/
static void
entry = gopherState->entry;
- if (gopherState->conversion == gopher_ds::HTML_INDEX_PAGE) {
+ if (gopherState->conversion == GopherStateData::HTML_INDEX_PAGE) {
char *html_url = html_quote(entry->url());
gopherHTMLHeader(entry, "Gopher Index %s", html_url);
storeAppendPrintf(entry,
return;
}
- if (gopherState->conversion == gopher_ds::HTML_CSO_PAGE) {
+ if (gopherState->conversion == GopherStateData::HTML_CSO_PAGE) {
char *html_url = html_quote(entry->url());
gopherHTMLHeader(entry, "CSO Search of %s", html_url);
storeAppendPrintf(entry,
String outbuf;
if (!gopherState->HTML_header_added) {
- if (gopherState->conversion == gopher_ds::HTML_CSO_RESULT)
+ if (gopherState->conversion == GopherStateData::HTML_CSO_RESULT)
gopherHTMLHeader(entry, "CSO Search Result", NULL);
else
gopherHTMLHeader(entry, "Gopher Menu", NULL);
switch (gopherState->conversion) {
- case gopher_ds::HTML_INDEX_RESULT:
+ case GopherStateData::HTML_INDEX_RESULT:
- case gopher_ds::HTML_DIR: {
+ case GopherStateData::HTML_DIR: {
tline = line;
gtype = *tline;
++tline;
break;
} /* HTML_DIR, HTML_INDEX_RESULT */
- case gopher_ds::HTML_CSO_RESULT: {
+ case GopherStateData::HTML_CSO_RESULT: {
if (line[0] == '-') {
int code, recno;
char *s_code, *s_recno, *result;
return;
}
-/// \ingroup ServerProtocolGopherInternal
static void
gopherTimeout(const CommTimeoutCbParams &io)
{
}
/**
- \ingroup ServerProtocolGopherInternal
* This will be called when data is ready to be read from fd.
* Read until error or connection closed.
*/
/* Connection closed; retrieval done. */
/* flush the rest of data in temp buf if there is one. */
- if (gopherState->conversion != gopher_ds::NORMAL)
+ if (gopherState->conversion != GopherStateData::NORMAL)
gopherEndHTML(gopherState);
entry->timestampsSet();
gopherState->fwd->complete();
gopherState->serverConn->close();
} else {
- if (gopherState->conversion != gopher_ds::NORMAL) {
+ if (gopherState->conversion != GopherStateData::NORMAL) {
gopherToHTML(gopherState, buf, len);
} else {
entry->append(buf, len);
}
/**
- \ingroup ServerProtocolGopherInternal
* This will be called when request write is complete. Schedule read of reply.
*/
static void
case GOPHER_DIRECTORY:
/* we got to convert it first */
- gopherState->conversion = gopher_ds::HTML_DIR;
+ gopherState->conversion = GopherStateData::HTML_DIR;
gopherState->HTML_header_added = 0;
break;
case GOPHER_INDEX:
/* we got to convert it first */
- gopherState->conversion = gopher_ds::HTML_INDEX_RESULT;
+ gopherState->conversion = GopherStateData::HTML_INDEX_RESULT;
gopherState->HTML_header_added = 0;
break;
case GOPHER_CSO:
/* we got to convert it first */
- gopherState->conversion = gopher_ds::HTML_CSO_RESULT;
+ gopherState->conversion = GopherStateData::HTML_CSO_RESULT;
gopherState->cso_recno = 0;
gopherState->HTML_header_added = 0;
break;
default:
- gopherState->conversion = gopher_ds::NORMAL;
+ gopherState->conversion = GopherStateData::NORMAL;
entry->flush();
}
}
/**
- \ingroup ServerProtocolGopherInternal
* This will be called when connect completes. Write request.
*/
static void
gopherState->entry->makePublic();
}
-/// \ingroup ServerProtocolGopherInternal
-CBDATA_TYPE(GopherStateData);
-
-/// \ingroup ServerProtocolGopherAPI
void
gopherStart(FwdState * fwd)
{
- StoreEntry *entry = fwd->entry;
- GopherStateData *gopherState;
- CBDATA_INIT_TYPE(GopherStateData);
- gopherState = cbdataAlloc(GopherStateData);
- gopherState->buf = (char *)memAllocate(MEM_4K_BUF);
-
- entry->lock("gopherState");
- gopherState->entry = entry;
-
- gopherState->fwd = fwd;
+ GopherStateData *gopherState = new GopherStateData(fwd);
- debugs(10, 3, "gopherStart: " << entry->url() );
+ debugs(10, 3, gopherState->entry->url());
++ statCounter.server.all.requests;
gopherMimeCreate(gopherState);
if (gopherState->type_id == GOPHER_INDEX) {
- gopherState->conversion = gopher_ds::HTML_INDEX_PAGE;
+ gopherState->conversion = GopherStateData::HTML_INDEX_PAGE;
} else {
if (gopherState->type_id == GOPHER_CSO) {
- gopherState->conversion = gopher_ds::HTML_CSO_PAGE;
+ gopherState->conversion = GopherStateData::HTML_CSO_PAGE;
} else {
- gopherState->conversion = gopher_ds::HTML_INDEX_PAGE;
+ gopherState->conversion = GopherStateData::HTML_INDEX_PAGE;
}
}