Пример #1
0
/*	Parse a document in memory given format and memory block pointer
**
**   This routine is responsible for creating and PRESENTING any
**   graphic (or other) objects described by the file.
**
**  State of memory and target stream on entry:
**			HTChunk* (chunk) assumed valid,
**			target (sink) usually NULL (will call stream stack).
**
**  Return values:
**	-501		Stream stack failed (cannot present or convert).
**	HT_LOADED	All data sent.
**
**  State of memory and target stream on return:
**	always		chunk unchanged; target freed, aborted, or NULL.
*/
PUBLIC int HTParseMem ARGS5(
	HTFormat,		rep_in,
	HTFormat,		format_out,
	HTParentAnchor *,	anchor,
	HTChunk *,		chunk,
	HTStream *,		sink)
{
    HTStream * stream;
    HTStreamClass targetClass;
    int rv;

    stream = HTStreamStack(rep_in, format_out, sink, anchor);
    if (!stream) {
	char *buffer = 0;
	HTSprintf0(&buffer, CANNOT_CONVERT_I_TO_O,
		   HTAtom_name(rep_in), HTAtom_name(format_out));
	CTRACE((tfp, "HTFormat(in HTParseMem): %s\n", buffer));
	rv = HTLoadError(sink, 501, buffer);
	FREE(buffer);
	return rv;
    }

    /* Push the data down the stream
    */
    targetClass = *(stream->isa);
    rv = HTMemCopy(chunk, stream);
    (*targetClass._free)(stream);
    return HT_LOADED;
}
Пример #2
0
/*	Parse a file given format and file pointer
**
**   This routine is responsible for creating and PRESENTING any
**   graphic (or other) objects described by the file.
**
**   The file number given is assumed to be a TELNET stream ie containing
**   CRLF at the end of lines which need to be stripped to LF for unix
**   when the format is textual.
**
*/
PUBLIC int HTParseFile ARGS6(
	HTFormat,		format_in,
	HTFormat,		format_out,
	HTParentAnchor *,	anchor,
	FILE *,			fp,
	HTStream*,		sink,
        int,                    compressed)
{
    HTStream * stream;
    HTStreamClass targetClass;    
    
    stream = HTStreamStack(format_in,
                           format_out,
                           compressed,
                           sink , anchor);
    
    if (!stream) {
        char buffer[1024];	/* @@@@@@@@ */
	sprintf(buffer, "Sorry, can't convert from %s to %s.",
		HTAtom_name(format_in), HTAtom_name(format_out));
#ifndef DISABLE_TRACE
	if (www2Trace) fprintf(stderr, "HTFormat(in HTParseFile): %s\n", buffer);
#endif
        return HTLoadError(sink, 501, buffer);
    }
    
    targetClass = *(stream->isa);	/* Copy pointers to procedures */
    HTFileCopy(fp, stream);
    (*targetClass.end_document)(stream);
    (*targetClass.free)(stream);
    
    return HT_LOADED;
}
Пример #3
0
/*	Parse a file given format and file pointer
**
**   This routine is responsible for creating and PRESENTING any
**   graphic (or other) objects described by the file.
**
**   The file number given is assumed to be a TELNET stream ie containing
**   CRLF at the end of lines which need to be stripped to \n for unix
**   when the format is textual.
**
**  State of file and target stream on entry:
**			FILE* (fp) assumed open,
**			target (sink) usually NULL (will call stream stack).
**
**  Return values:
**	-501		Stream stack failed (cannot present or convert).
**	-1		Download cancelled.
**	HT_NO_DATA	Error before any data read.
**	HT_PARTIAL_CONTENT	Interruption or error after some data read.
**	HT_LOADED	Normal end of file indication on reading.
**
**  State of file and target stream on return:
**	always		fp still open; target freed, aborted, or NULL.
*/
PUBLIC int HTParseFile ARGS5(
	HTFormat,		rep_in,
	HTFormat,		format_out,
	HTParentAnchor *,	anchor,
	FILE *,			fp,
	HTStream*,		sink)
{
    HTStream * stream;
    HTStreamClass targetClass;
    int rv;

#ifdef SH_EX		/* 1998/01/04 (Sun) 16:04:09 */
    if (fp == NULL)
	return HT_LOADED;
#endif

    stream = HTStreamStack(rep_in, format_out, sink, anchor);

    if (!stream) {
	char *buffer = 0;
	if (LYCancelDownload) {
	    LYCancelDownload = FALSE;
	    return -1;
	}
	HTSprintf0(&buffer, CANNOT_CONVERT_I_TO_O,
		HTAtom_name(rep_in), HTAtom_name(format_out));
	CTRACE((tfp, "HTFormat(in HTParseFile): %s\n", buffer));
	rv = HTLoadError(sink, 501, buffer);
	FREE(buffer);
	return rv;
    }

    /*	Push the data down the stream
    **
    **	@@  Bug:  This decision ought to be made based on "encoding"
    **	rather than on content-type.  @@@  When we handle encoding.
    **	The current method smells anyway.
    */
    targetClass = *(stream->isa);	/* Copy pointers to procedures */
    rv = HTFileCopy(fp, stream);
    if (rv == -1 || rv == HT_INTERRUPTED) {
	(*targetClass._abort)(stream, NULL);
    } else {
	(*targetClass._free)(stream);
    }

    if (rv == -1)
	return HT_NO_DATA;
    else if (rv == HT_INTERRUPTED || (rv > 0 && rv != HT_LOADED))
	return HT_PARTIAL_CONTENT;
    else
	return HT_LOADED;
}
Пример #4
0
/*	Parse a socket given format and file number
**
**   This routine is responsible for creating and PRESENTING any
**   graphic (or other) objects described by the file.
**
**   The file number given is assumed to be a TELNET stream ie containing
**   CRLF at the end of lines which need to be stripped to LF for unix
**   when the format is textual.
**
*/
PUBLIC int HTParseSocket ARGS6(
	HTFormat,		format_in,
	HTFormat,		format_out,
	HTParentAnchor *,	anchor,
	int,			file_number,
	HTStream*,		sink,
        int,                    compressed)
{
  HTStream * stream;
  HTStreamClass targetClass;    
  int rv;
  
  stream = HTStreamStack(format_in,
                         format_out,
                         compressed,
                         sink, anchor);
  
  if (!stream) 
    {
      char buffer[1024];	/* @@@@@@@@ */
      sprintf(buffer, "Sorry, can't convert from %s to %s.",
              HTAtom_name(format_in), HTAtom_name(format_out));
#ifndef DISABLE_TRACE
      if (www2Trace) fprintf(stderr, "HTFormat: %s\n", buffer);
#endif
      return HTLoadError(sink, 501, buffer);
    }
    
  targetClass = *(stream->isa);	/* Copy pointers to procedures */
  rv = HTCopy(file_number, stream, 0);
  if (rv == -1)
    {
      /* handle_interrupt should have been done in HTCopy */
      /* (*targetClass.handle_interrupt)(stream); */
      return HT_INTERRUPTED;
    }

  (*targetClass.end_document)(stream);

  /* New thing: we force close the data socket here, so that if
     an external viewer gets forked off in the free method below,
     the connection doesn't remain upon until the child exits --
     which it does if we don't do this. */
  NETCLOSE (file_number);

  (*targetClass.free)(stream);
    
  return HT_LOADED;
}
Пример #5
0
int LYLoadKeymap( char *arg, HTParentAnchor *anAnchor, HTFormat format_out, HTStream *sink )
{
  HTFormat format_in = HTAtom_for( "text/html" );
  HTStream *target;
  char *buf = 0;
  int i;
  target = HTStreamStack( format_in, format_out, &sink[0]._HTStream, anAnchor );
  if ( target == 0 || target == 0 )
  {
    HTSprintf0( &buf, gettext( "Sorry, no known way of converting %s to %s." ), format_in->name, format_out->name );
    HTAlert( buf );
    if ( buf )
    {
      free( buf );
      buf = 0;
    }
    return -29999;
  }
  else
  {
    anAnchor->no_cache = 1;
    HTSprintf0( &buf, "<html>\n<head>\n<title>%s</title>\n</head>\n<body>\n", gettext( "Current Key Map" ) );
    ebx( target, buf, strlen( buf ) );
    HTSprintf0( &buf, "<pre>\n" );
    ebx( target, buf, strlen( buf ) );
    i = 98;
    for ( ; i <= 123; i++ )
    {
      print_binding( target, i, 1 );
      // i++;
    }
    i = 1;
    for ( ; i <= 660; i++ )
    {
      if ( ( i > 127 || i <= 32 || !( *(short*)(*(int*)(__ctype_b_loc( )) + ( ( i + -1 ) * 2 )) & 1024 ) ) && ( LYUseMouse || keymap[ i ] != 84 ) )
        print_binding( target, i, 0 );
      // i++;
    }
    HTSprintf0( &buf, "&lt;/pre&gt;\n&lt;/body&gt;\n&lt;/html&gt;\n" );
    ebx( target, buf, strlen( buf ) );
    ;
  }
}
Пример #6
0
/*
**	Scan the request line for METHOD, URI and VERSION
**	Returns:	HT_OK		if 1.x request and OK
**			HT_LOADED     	if 0.9 request and OK
**			HT_ERROR	if invalid request line
*/
PRIVATE int ParseRequest (HTStream * me)
{
    HTRequest * client = HTList_firstObject(me->http->clients);
    char * line = HTChunk_data(me->buffer);
    char * method_str = HTNextField(&line);
    char * request_uri = HTNextField(&line);
    char * version_str = HTNextField(&line);
    HTMethod method;

    /* Check if method is allowed */
    if (!method_str || (method = HTMethod_enum(method_str))==METHOD_INVALID) {
        HTRequest_addError(client, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
                           NULL, 0, "ParseRequest");
        return HT_ERROR;
    }
    HTRequest_setMethod(client, method);

    /* Find an anchor for the request URI */
    if (request_uri) {
        char * uri = HTParse(request_uri, "file:", PARSE_ALL);
        HTRequest_setAnchor(client, HTAnchor_findAddress(uri));
        HT_FREE(uri);
    } else {
        HTRequest_addError(client, ERR_FATAL, NO, HTERR_BAD_REQUEST,
                           NULL, 0, "ParseRequest");
        return HT_ERROR;
    }

    /* Get ready to get the rest of the request */
    if (version_str) {
        me->target = HTStreamStack(WWW_MIME_HEAD,
                                   HTRequest_debugFormat(client),
                                   HTRequest_debugStream(client),
                                   client, NO);
        return HT_OK;
    } else {
        HTRequest_addError(client, ERR_FATAL, NO, HTERR_BAD_VERSION,
                           NULL, 0, "ParseRequest");
        return HT_ERROR;
    }
}
Пример #7
0
/*	ScanResponse
**	------------
**	Analyzes the response from the NNTP server.
**	We only expect one line response codes.
**	Returns HT_LOADED if OK, HT_ERROR if error
*/
PRIVATE int ScanResponse (HTStream * me)
{
    news_info *news = me->news;
    *(me->buffer+me->buflen) = '\0';
    if (isdigit((int) *(me->buffer))) sscanf(me->buffer, "%d", &news->repcode);
    me->buflen = 0;
    news->reply = me->buffer+4;
    HTTRACE(PROT_TRACE, "News Rx..... `%s\'\n" _ news->reply);

    /* If 2xx code and we expect data then go into semi-transparent mode */
    if (me->news->format && news->repcode/100 == 2) {
	HTRequest *req = me->request;
	me->target = HTStreamStack(me->news->format, req->output_format,
				   req->output_stream, req, NO);
	me->semi_trans = YES;
	if (!me->target) return HT_ERROR;
    } else if (news->repcode/100 == 4) {
	HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_FOUND,
			   news->reply, strlen(news->reply), "ScanResponse");
    }
    return HT_LOADED;
}
Пример #8
0
/*	Parse a socket given format and file number
**
**   This routine is responsible for creating and PRESENTING any
**   graphic (or other) objects described by the file.
**
**   The file number given is assumed to be a TELNET stream ie containing
**   CRLF at the end of lines which need to be stripped to LF for unix
**   when the format is textual.
**
**  State of socket and target stream on entry:
**			socket (file_number) assumed open,
**			target (sink) usually NULL (will call stream stack).
**
**  Return values:
**	HT_INTERRUPTED  Interruption or error after some data received.
**	-501		Stream stack failed (cannot present or convert).
**	-2		Unexpected disconnect before any data received.
**	-1		Stream stack failed (cannot present or convert), or
**			Interruption or error before any data received, or
**			(UNIX) other read error before any data received, or
**			download cancelled.
**	HT_LOADED	Normal close of socket (end of file indication
**			received), or
**			unexpected disconnect after some data received, or
**			other read error after some data received, or
**			(not UNIX) other read error before any data received.
**
**  State of socket and target stream on return depends on return value:
**	HT_INTERRUPTED	socket still open, target aborted.
**	-501		socket still open, target stream NULL.
**	-2		socket still open, target freed.
**	-1		socket still open, target stream aborted or NULL.
**	otherwise	socket closed,	target stream freed.
*/
PUBLIC int HTParseSocket ARGS5(
	HTFormat,		rep_in,
	HTFormat,		format_out,
	HTParentAnchor *,	anchor,
	int,			file_number,
	HTStream*,		sink)
{
    HTStream * stream;
    HTStreamClass targetClass;
    int rv;

    stream = HTStreamStack(rep_in, format_out, sink, anchor);

    if (!stream) {
	char *buffer = 0;
	if (LYCancelDownload) {
	    LYCancelDownload = FALSE;
	    return -1;
	}
	HTSprintf0(&buffer, CANNOT_CONVERT_I_TO_O,
		HTAtom_name(rep_in), HTAtom_name(format_out));
	CTRACE((tfp, "HTFormat: %s\n", buffer));
	rv = HTLoadError(sink, 501, buffer); /* returns -501 */
	FREE(buffer);
    } else {
	/*
	** Push the data, don't worry about CRLF we can strip them later.
	*/
	targetClass = *(stream->isa);	/* Copy pointers to procedures */
	rv = HTCopy(anchor, file_number, NULL, stream);
	if (rv != -1 && rv != HT_INTERRUPTED)
	    (*targetClass._free)(stream);
    }
    return rv;
    /* Originally:  full: HT_LOADED;  partial: HT_INTERRUPTED;  no bytes: -1 */
}
Пример #9
0
PRIVATE int HTBoundary_put_block (HTStream * me, const char * b, int l)
{
    const char *start = b;
    const char *end = b;
    while (l-- > 0) {
	if (me->state == EOL_FCR) {
	    me->state = (*b == LF) ? EOL_FLF : EOL_BEGIN;
	} else if (me->state == EOL_FLF) {
	    if (me->dash == 2) {
		while (l>0 && *me->bpos && *me->bpos==*b) l--, me->bpos++, b++;
		if (!*me->bpos) {
		    HTTRACE(STREAM_TRACE, "Boundary.... `%s\' found\n" _ me->boundary);
		    me->bpos = me->boundary;
		    me->body = YES;
		    me->state = EOL_DOT;
		} else if (l>0) {
		    me->dash = 0;
		    me->bpos = me->boundary;
		    me->state = EOL_BEGIN;
		}
	    }
	    if (*b == '-') {
		me->dash++;
	    } else if (*b != CR && *b != LF) {
		me->dash = 0;
		me->state = EOL_BEGIN;
	    }
	} else if (me->state == EOL_SLF) {	    /* Look for closing '--' */
	    if (me->dash == 4) {
		if (end > start) {
		    int status = PUTBLOCK(start, end-start);
		    if (status != HT_OK) return status;
		}
		HTTRACE(STREAM_TRACE, "Boundary.... Ending\n");
		start = b;
		me->dash = 0;
		me->state = EOL_BEGIN;
	    }
	    if (*b == '-') {
		me->dash++;
	    } else if (*b != CR && *b != LF) {
		me->dash = 0;
		me->state = EOL_BEGIN;
	    }
	    me->body = NO;
	} else if (me->state == EOL_DOT) {
	    int status;
	    if (me->body) {
		if (me->target) FREE_TARGET;
		me->target = HTStreamStack(WWW_MIME,me->format,
					   HTMerge(me->orig_target, 2),
					   me->request, YES);
		if (end > start) {
		    if ((status = PUTBLOCK(start, end-start)) != HT_OK)
			return status;
		}
	    } else {
		if (me->debug)
		    if ((status = PUTDEBUG(start, end-start)) != HT_OK)
			return status;
	    }
	    start = b;
	    if (*b == '-') me->dash++;
	    me->state = EOL_SLF;
	} else if (*b == CR) {
	    me->state = EOL_FCR;
	    end = b;
	} else if (*b == LF) {
	    if (me->state != EOL_FCR) end = b;
	    me->state = EOL_FLF;
	}
	b++;
    }
    return (start<b && me->body) ? PUTBLOCK(start, b-start) : HT_OK;
}
Пример #10
0
static int LYLoadCGI(const char *arg,
		     HTParentAnchor *anAnchor,
		     HTFormat format_out,
		     HTStream *sink)
{
    int status = 0;

#ifdef LYNXCGI_LINKS
#ifndef VMS
    char *cp;
    struct stat stat_buf;
    char *pgm = NULL;		/* executable */
    char *pgm_args = NULL;	/* and its argument(s) */
    int statrv;
    char *orig_pgm = NULL;	/* Path up to ? as given, URL-escaped */
    char *document_root = NULL;	/* Corrected value of DOCUMENT_ROOT  */
    char *path_info = NULL;	/* PATH_INFO extracted from pgm      */
    char *pgm_buff = NULL;	/* PATH_INFO extraction buffer       */
    char *path_translated;	/* From document_root/path_info      */

    if (isEmpty(arg) || strlen(arg) <= 8) {
	HTAlert(BAD_REQUEST);
	status = -2;
	return (status);

    } else {
	if (StrNCmp(arg, "lynxcgi://localhost", 19) == 0) {
	    StrAllocCopy(pgm, arg + 19);
	} else {
	    StrAllocCopy(pgm, arg + 8);
	}
	if ((cp = StrChr(pgm, '?')) != NULL) {	/* Need to terminate executable */
	    *cp++ = '\0';
	    pgm_args = cp;
	}
    }

    StrAllocCopy(orig_pgm, pgm);
    if (trimPoundSelector(pgm) != NULL) {
	/*
	 * Strip a #fragment from path.  In this case any pgm_args found above
	 * will also be bogus, since the '?' came after the '#' and is part of
	 * the fragment.  Note that we don't handle the case where a '#'
	 * appears after a '?' properly according to URL rules.  - kw
	 */
	pgm_args = NULL;
    }
    HTUnEscape(pgm);

    /* BEGIN WebSter Mods */
    /* If pgm is not stat-able, see if PATH_INFO data is at the end of pgm */
    if ((statrv = stat(pgm, &stat_buf)) < 0) {
	StrAllocCopy(pgm_buff, pgm);
	while (statrv < 0 || (statrv = stat(pgm_buff, &stat_buf)) < 0) {
	    if ((cp = strrchr(pgm_buff, '/')) != NULL) {
		*cp = '\0';
		statrv = 1;	/* force new stat()  - kw */
	    } else {
		PERROR("strrchr(pgm_buff, '/') returned NULL");
		break;
	    }
	}

	if (statrv < 0) {
	    /* Did not find PATH_INFO data */
	    PERROR("stat() of pgm_buff failed");
	} else {
	    /* Found PATH_INFO data.  Strip it off of pgm and into path_info. */
	    StrAllocCopy(path_info, pgm + strlen(pgm_buff));
	    /* The following is safe since pgm_buff was derived from pgm
	       by stripping stuff off its end and by HTUnEscaping, so we
	       know we have enough memory allocated for pgm.  Note that
	       pgm_args may still point into that memory, so we cannot
	       reallocate pgm here. - kw */
	    strcpy(pgm, pgm_buff);
	    CTRACE((tfp,
		    "LYNXCGI: stat() of %s succeeded, path_info=\"%s\".\n",
		    pgm_buff, path_info));
	}
	FREE(pgm_buff);
    }
    /* END WebSter Mods */

    if (statrv != 0) {
	/*
	 * Neither the path as given nor any components examined by backing up
	 * were stat()able.  - kw
	 */
	HTAlert(gettext("Unable to access cgi script"));
	PERROR("stat() failed");
	status = -4;

    } else
#ifdef _WINDOWS			/* 1998/01/14 (Wed) 09:16:04 */
#define isExecutable(mode) (mode & (S_IXUSR))
#else
#define isExecutable(mode) (mode & (S_IXUSR|S_IXGRP|S_IXOTH))
#endif
    if (!(S_ISREG(stat_buf.st_mode) && isExecutable(stat_buf.st_mode))) {
	/*
	 * Not a runnable file, See if we can load it using "file:" code.
	 */
	char *new_arg = NULL;

	/*
	 * But try "file:" only if the file we are looking at is the path as
	 * given (no path_info was extracted), otherwise it will be to
	 * confusing to know just what file is loaded.  - kw
	 */
	if (path_info) {
	    CTRACE((tfp,
		    "%s is not a file and %s not an executable, giving up.\n",
		    orig_pgm, pgm));
	    FREE(path_info);
	    FREE(pgm);
	    FREE(orig_pgm);
	    status = -4;
	    return (status);
	}

	LYLocalFileToURL(&new_arg, orig_pgm);

	CTRACE((tfp, "%s is not an executable file, passing the buck.\n", arg));
	status = HTLoadFile(new_arg, anAnchor, format_out, sink);
	FREE(new_arg);

    } else if (path_info &&
	       anAnchor != HTMainAnchor &&
	       !(reloading && anAnchor->document) &&
	       strcmp(arg, HTLoadedDocumentURL()) &&
	       HText_AreDifferent(anAnchor, arg) &&
	       HTUnEscape(orig_pgm) &&
	       !can_exec_cgi(orig_pgm, "")) {
	/*
	 * If we have extra path info and are not just reloading the current,
	 * check the full file path (after unescaping) now to catch forbidden
	 * segments.  - kw
	 */
	status = HT_NOT_LOADED;

    } else if (no_lynxcgi) {
	HTUserMsg(CGI_DISABLED);
	status = HT_NOT_LOADED;

    } else if (no_bookmark_exec &&
	       anAnchor != HTMainAnchor &&
	       !(reloading && anAnchor->document) &&
	       strcmp(arg, HTLoadedDocumentURL()) &&
	       HText_AreDifferent(anAnchor, arg) &&
	       HTLoadedDocumentBookmark()) {
	/*
	 * If we are reloading a lynxcgi document that had already been loaded,
	 * the various checks above should allow it even if no_bookmark_exec is
	 * TRUE an we are not now coming from a bookmark page.  - kw
	 */
	HTUserMsg(BOOKMARK_EXEC_DISABLED);
	status = HT_NOT_LOADED;

    } else if (anAnchor != HTMainAnchor &&
	       !(reloading && anAnchor->document) &&
	       strcmp(arg, HTLoadedDocumentURL()) &&
	       HText_AreDifferent(anAnchor, arg) &&
	       !can_exec_cgi(pgm, pgm_args)) {
	/*
	 * If we are reloading a lynxcgi document that had already been loaded,
	 * the various checks above should allow it even if exec_ok() would
	 * reject it because we are not now coming from a document with a URL
	 * allowed by TRUSTED_LYNXCGI rules.  - kw
	 */
	status = HT_NOT_LOADED;

    } else {
	HTFormat format_in;
	HTStream *target = NULL;	/* Unconverted data */
	int fd1[2], fd2[2];
	char buf[MAX_LINE];
	int pid;

#ifdef HAVE_TYPE_UNIONWAIT
	union wait wstatus;

#else
	int wstatus;
#endif

	fd1[0] = -1;
	fd1[1] = -1;
	fd2[0] = -1;
	fd2[1] = -1;

	if (anAnchor->isHEAD || keep_mime_headers) {

	    /* Show output as plain text */
	    format_in = WWW_PLAINTEXT;
	} else {

	    /* Decode full HTTP response */
	    format_in = HTAtom_for("www/mime");
	}

	target = HTStreamStack(format_in,
			       format_out,
			       sink, anAnchor);

	if (!target || target == NULL) {
	    char *tmp = 0;

	    HTSprintf0(&tmp, CANNOT_CONVERT_I_TO_O,
		       HTAtom_name(format_in),
		       HTAtom_name(format_out));
	    HTAlert(tmp);
	    FREE(tmp);
	    status = HT_NOT_LOADED;

	} else if (anAnchor->post_data && pipe(fd1) < 0) {
	    HTAlert(CONNECT_SET_FAILED);
	    PERROR("pipe() failed");
	    status = -3;

	} else if (pipe(fd2) < 0) {
	    HTAlert(CONNECT_SET_FAILED);
	    PERROR("pipe() failed");
	    close(fd1[0]);
	    close(fd1[1]);
	    status = -3;

	} else {
	    static BOOL first_time = TRUE;	/* One time setup flag */

	    if (first_time) {	/* Set up static environment variables */
		first_time = FALSE;	/* Only once */

		add_environment_value("REMOTE_HOST=localhost");
		add_environment_value("REMOTE_ADDR=127.0.0.1");

		HTSprintf0(&user_agent, "HTTP_USER_AGENT=%s/%s libwww/%s",
			   LYNX_NAME, LYNX_VERSION, HTLibraryVersion);
		add_environment_value(user_agent);

		HTSprintf0(&server_software, "SERVER_SOFTWARE=%s/%s",
			   LYNX_NAME, LYNX_VERSION);
		add_environment_value(server_software);
	    }
	    fflush(stdout);
	    fflush(stderr);
	    CTRACE_FLUSH(tfp);

	    if ((pid = fork()) > 0) {	/* The good, */
		ssize_t chars;
		off_t total_chars;

		close(fd2[1]);

		if (anAnchor->post_data) {
		    ssize_t written;
		    int remaining, total_written = 0;

		    close(fd1[0]);

		    /* We have form data to push across the pipe */
		    if (TRACE) {
			CTRACE((tfp,
				"LYNXCGI: Doing post, content-type '%s'\n",
				anAnchor->post_content_type));
			CTRACE((tfp, "LYNXCGI: Writing:\n"));
			trace_bstring(anAnchor->post_data);
			CTRACE((tfp, "----------------------------------\n"));
		    }
		    remaining = BStrLen(anAnchor->post_data);
		    while ((written = write(fd1[1],
					    BStrData(anAnchor->post_data) + total_written,
					    (size_t) remaining)) != 0) {
			if (written < 0) {
#ifdef EINTR
			    if (errno == EINTR)
				continue;
#endif /* EINTR */
#ifdef ERESTARTSYS
			    if (errno == ERESTARTSYS)
				continue;
#endif /* ERESTARTSYS */
			    PERROR("write() of POST data failed");
			    break;
			}
			CTRACE((tfp, "LYNXCGI: Wrote %d bytes of POST data.\n",
				(int) written));
			total_written += (int) written;
			remaining -= (int) written;
			if (remaining == 0)
			    break;
		    }
		    if (remaining != 0) {
			CTRACE((tfp, "LYNXCGI: %d bytes remain unwritten!\n",
				remaining));
		    }
		    close(fd1[1]);
		}

		HTReadProgress(total_chars = 0, (off_t) 0);
		while ((chars = read(fd2[0], buf, sizeof(buf))) != 0) {
		    if (chars < 0) {
#ifdef EINTR
			if (errno == EINTR)
			    continue;
#endif /* EINTR */
#ifdef ERESTARTSYS
			if (errno == ERESTARTSYS)
			    continue;
#endif /* ERESTARTSYS */
			PERROR("read() of CGI output failed");
			break;
		    }
		    total_chars += (int) chars;
		    HTReadProgress(total_chars, (off_t) 0);
		    CTRACE((tfp, "LYNXCGI: Rx: %.*s\n", (int) chars, buf));
		    (*target->isa->put_block) (target, buf, (int) chars);
		}

		if (chars < 0 && total_chars == 0) {
		    status = HT_NOT_LOADED;
		    (*target->isa->_abort) (target, NULL);
		    target = NULL;
		} else if (chars != 0) {
		    status = HT_PARTIAL_CONTENT;
		} else {
		    status = HT_LOADED;
		}

#ifndef HAVE_WAITPID
		while (wait(&wstatus) != pid) ;		/* do nothing */
#else
		while (-1 == waitpid(pid, &wstatus, 0)) {	/* wait for child */
#ifdef EINTR
		    if (errno == EINTR)
			continue;
#endif /* EINTR */
#ifdef ERESTARTSYS
		    if (errno == ERESTARTSYS)
			continue;
#endif /* ERESTARTSYS */
		    break;
		}
#endif /* !HAVE_WAITPID */
		close(fd2[0]);

	    } else if (pid == 0) {	/* The Bad, */
		char **argv = NULL;
		int argv_cnt = 3;	/* name, one arg and terminator */
		char **cur_argv = NULL;
		int exec_errno;

		/* Set up output pipe */
		close(fd2[0]);
		dup2(fd2[1], fileno(stdout));	/* Should check success code */
		dup2(fd2[1], fileno(stderr));
		close(fd2[1]);

		if (non_empty(language)) {
		    HTSprintf0(&accept_language, "HTTP_ACCEPT_LANGUAGE=%s", language);
		    add_environment_value(accept_language);
		}

		if (non_empty(pref_charset)) {
		    cp = NULL;
		    StrAllocCopy(cp, "HTTP_ACCEPT_CHARSET=");
		    StrAllocCat(cp, pref_charset);
		    add_environment_value(cp);
		}

		if (anAnchor->post_data &&
		    anAnchor->post_content_type) {
		    cp = NULL;
		    StrAllocCopy(cp, "CONTENT_TYPE=");
		    StrAllocCat(cp, anAnchor->post_content_type);
		    add_environment_value(cp);
		}

		if (anAnchor->post_data) {	/* post script, read stdin */
		    close(fd1[1]);
		    dup2(fd1[0], fileno(stdin));
		    close(fd1[0]);

		    /* Build environment variables */

		    add_environment_value("REQUEST_METHOD=POST");

		    HTSprintf0(&post_len, "CONTENT_LENGTH=%d",
			       BStrLen(anAnchor->post_data));
		    add_environment_value(post_len);
		} else {
		    close(fileno(stdin));

		    if (anAnchor->isHEAD) {
			add_environment_value("REQUEST_METHOD=HEAD");
		    }
		}

		/*
		 * Set up argument line, mainly for <index> scripts
		 */
		if (pgm_args != NULL) {
		    for (cp = pgm_args; *cp != '\0'; cp++) {
			if (*cp == '+') {
			    argv_cnt++;
			}
		    }
		}

		argv = (char **) malloc((unsigned) argv_cnt * sizeof(char *));

		if (argv == NULL) {
		    outofmem(__FILE__, "LYCgi");
		}
		assert(argv != NULL);

		cur_argv = argv + 1;	/* For argv[0] */
		if (pgm_args != NULL) {
		    char *cr;

		    /* Data for a get/search form */
		    if (is_www_index) {
			add_environment_value("REQUEST_METHOD=SEARCH");
		    } else if (!anAnchor->isHEAD && !anAnchor->post_data) {
			add_environment_value("REQUEST_METHOD=GET");
		    }

		    cp = NULL;
		    StrAllocCopy(cp, "QUERY_STRING=");
		    StrAllocCat(cp, pgm_args);
		    add_environment_value(cp);

		    /*
		     * Split up arguments into argv array
		     */
		    cp = pgm_args;
		    cr = cp;
		    while (1) {
			if (*cp == '\0') {
			    *(cur_argv++) = HTUnEscape(cr);
			    break;

			} else if (*cp == '+') {
			    *cp++ = '\0';
			    *(cur_argv++) = HTUnEscape(cr);
			    cr = cp;
			}
			cp++;
		    }
		} else if (!anAnchor->isHEAD && !anAnchor->post_data) {
		    add_environment_value("REQUEST_METHOD=GET");
		}
		*cur_argv = NULL;	/* Terminate argv */
		argv[0] = pgm;

		/* Begin WebSter Mods  -jkt */
		if (LYCgiDocumentRoot != NULL) {
		    /* Add DOCUMENT_ROOT to env */
		    cp = NULL;
		    StrAllocCopy(cp, "DOCUMENT_ROOT=");
		    StrAllocCat(cp, LYCgiDocumentRoot);
		    add_environment_value(cp);
		}
		if (path_info != NULL) {
		    /* Add PATH_INFO to env */
		    cp = NULL;
		    StrAllocCopy(cp, "PATH_INFO=");
		    StrAllocCat(cp, path_info);
		    add_environment_value(cp);
		}
		if (LYCgiDocumentRoot != NULL && path_info != NULL) {
		    /* Construct and add PATH_TRANSLATED to env */
		    StrAllocCopy(document_root, LYCgiDocumentRoot);
		    LYTrimHtmlSep(document_root);
		    path_translated = document_root;
		    StrAllocCat(path_translated, path_info);
		    cp = NULL;
		    StrAllocCopy(cp, "PATH_TRANSLATED=");
		    StrAllocCat(cp, path_translated);
		    add_environment_value(cp);
		    FREE(path_translated);
		}
		/* End WebSter Mods  -jkt */

		execve(argv[0], argv, env);
		exec_errno = errno;
		PERROR("execve failed");
		printf("Content-Type: text/plain\r\n\r\n");
		if (!anAnchor->isHEAD) {
		    printf("exec of %s failed", pgm);
		    printf(": %s.\r\n", LYStrerror(exec_errno));
		}
		fflush(stdout);
		fflush(stderr);
		_exit(1);

	    } else {		/* and the Ugly */
		HTAlert(CONNECT_FAILED);
		PERROR("fork() failed");
		close(fd1[0]);
		close(fd1[1]);
		close(fd2[0]);
		close(fd2[1]);
		status = -1;
	    }

	}
	if (target != NULL) {
	    (*target->isa->_free) (target);
	}
    }
    FREE(path_info);
    FREE(pgm);
    FREE(orig_pgm);
#else /* VMS */
    HTStream *target;
    char *buf = 0;

    target = HTStreamStack(WWW_HTML,
			   format_out,
			   sink, anAnchor);

    HTSprintf0(&buf, "<html>\n<head>\n<title>%s</title>\n</head>\n<body>\n",
	       gettext("Good Advice"));
    PUTS(buf);

    HTSprintf0(&buf, "<h1>%s</h1>\n", gettext("Good Advice"));
    PUTS(buf);

    HTSprintf0(&buf, "%s <a\n",
	       gettext("An excellent http server for VMS is available via"));
    PUTS(buf);

    HTSprintf0(&buf,
	       "href=\"http://www.ecr6.ohio-state.edu/www/doc/serverinfo.html\"\n");
    PUTS(buf);

    HTSprintf0(&buf, ">%s</a>.\n", gettext("this link"));
    PUTS(buf);

    HTSprintf0(&buf, "<p>%s\n",
	       gettext("It provides state of the art CGI script support.\n"));
    PUTS(buf);

    HTSprintf0(&buf, "</body>\n</html>\n");
    PUTS(buf);

    (*target->isa->_free) (target);
    FREE(buf);
    status = HT_LOADED;
#endif /* VMS */
#else /* LYNXCGI_LINKS */
    HTUserMsg(CGI_NOT_COMPILED);
    status = HT_NOT_LOADED;
#endif /* LYNXCGI_LINKS */

    (void) arg;
    (void) anAnchor;
    (void) format_out;
    (void) sink;

    return (status);
}
Пример #11
0
PRIVATE int pumpData (HTStream * me)
{
    HTRequest * request = me->request;
    HTResponse * response = me->response;
    HTFormat format = HTResponse_format(response);
    HTList * te = HTResponse_transfer(response);
    HTList * ce = HTResponse_encoding(response);
    long length = HTResponse_length(response);
    HTStream * BlackHole = HTBlackHole();
    BOOL savestream = NO;
    me->transparent = YES;		  /* Pump rest of data right through */

    /*
    **  Cache the metainformation in the anchor object by copying
    **  it from the response object. This we do regardless if
    **  we have a persistent cache or not as the memory cache will
    **  use it as well. If we are updating a cache entry using
    **  byte ranges then we already have the metainformation and
    **  hence we can ignore the new one as it'd better be the same.
    */
    if (!(me->mode & HT_MIME_PARTIAL) &&
	HTResponse_isCachable(me->response) != HT_NO_CACHE)
	HTAnchor_update(HTRequest_anchor(request), me->response);

    /*
    **  If we asked only to read the header or footer or we used a HEAD
    **  method then we stop here as we don't expect any body part.
    */
    if (me->mode & (HT_MIME_HEADER | HT_MIME_FOOTER) ||
	HTRequest_method(request) == METHOD_HEAD) {
        HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE);
        if (cbf) (*cbf)(request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL);
        return HT_LOADED;
    }

    /*
    **  If we are paring a 1xx response then return HT_CONTINUE
    */
    if (me->mode & HT_MIME_CONT)
	return HT_CONTINUE;

    /*
    **  If we get a 101 Protocol Switch then we are done here
    **  but not done with the response (which we don't know
    **  how to go about parsing
    */
    if (me->mode & HT_MIME_UPGRADE) {
	me->hasBody = YES;
	return HT_OK;
    }

    /*
    **  If there is no content-length, no transfer encoding and no
    **  content type then we assume that there is no body part in
    **  the message and we can return HT_LOADED
    */
    {
	HTHost * host = HTNet_host(me->net);
	if (length<0 && te==NULL &&
	    HTHost_isPersistent(host) && !HTHost_closeNotification(host)) {
	    if (format != WWW_UNKNOWN) {
		HTTRACE(STREAM_TRACE, "MIME Parser. BAD - there seems to be a body but no length. This must be an HTTP/1.0 server pretending that it is HTTP/1.1\n");
		HTHost_setCloseNotification(host, YES);
	    } else {
                HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE);
                if (cbf) (*cbf)(request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL);
		HTTRACE(STREAM_TRACE, "MIME Parser. No body in this message\n");
		return HT_LOADED;
	    }
	}
    }

    /*
    **  Deal with the body
    */
    me->hasBody = YES;

    /*
    **  Handle any Content Type
    */
    if (!(me->mode & HT_MIME_PARTIAL) &&
	(format != WWW_UNKNOWN || length > 0 || te)) {
	HTStream * target;
	HTTRACE(STREAM_TRACE, "Building.... C-T stack from %s to %s\n" _ 
				  HTAtom_name(format) _ 
				  HTAtom_name(me->target_format));
	if ((target = HTStreamStack(format, me->target_format,
				    me->target, request, YES))==BlackHole) {
	    if (!savestream) {
                if (me->target) (*me->target->isa->abort)(me->target, NULL);
                me->target = me->save_stream(request, NULL,
					     format, me->target_format, me->target);
		savestream = YES;
	    }
	} else
	    me->target = target;
    }

    /*
    **  Handle any Content Encodings
    */
    HTTRACE(STREAM_TRACE, "Building.... Content-Decoding stack\n");
    if (ce) {
	HTStream * target = HTContentDecodingStack(ce, me->target, request, NULL);
	if (target == BlackHole) {
	    if (!savestream) {
		if (me->target) (*me->target->isa->abort)(me->target, NULL);
                me->target = me->save_stream(request, NULL,
					     format, me->target_format, me->target);
		savestream = YES;
	    }
	} else
	    me->target = target;
    }

    /*
    **  Can we cache the data object? If so then create a T stream and hook it 
    **  into the stream pipe. We do it before the transfer decoding so that we
    **  don't have to deal with that when we retrieve the object from cache.
    **  If we are appending to a cache entry then use a different stream than
    **  if creating a new entry.
    */
#ifndef NO_CACHE
    if (HTCacheMode_enabled()) {
	if (me->mode & HT_MIME_PARTIAL) {
	    HTStream * append = HTStreamStack(WWW_CACHE_APPEND,
					      me->target_format,
					      me->target, request, NO);
	    if (append) me->target = HTTee(me->target, append, NULL);
#if 0
	    /* @@ JK: change */
	    if (append) me->target = append;
#endif
	} else if (HTResponse_isCachable(me->response) == HT_CACHE_ALL) {
	    HTStream * cache = HTStreamStack(WWW_CACHE, me->target_format,
					     me->target, request, NO);
	    if (cache) me->target = HTTee(me->target, cache, NULL);
	}
    }
#endif
    
    /*
    **  Handle any Transfer Encodings
    */
    HTTRACE(STREAM_TRACE, "Building.... Transfer-Decoding stack\n");
    if (te) {
	HTStream * target = HTTransferDecodingStack(te, me->target, request, NULL);
	if (target == BlackHole) {
	    if (!savestream) {
		if (me->target) (*me->target->isa->abort)(me->target, NULL);
                me->target = me->save_stream(request, NULL,
					     format, me->target_format, me->target);
		savestream = YES;
	    }
	} else
	    me->target = target;
    }


    /*
    ** If we for some reason couldn't find a target stream
    */
    if (!me->target) me->target = HTBlackHole();
    return HT_OK;
}
Пример #12
0
}

static int LYLoadKeymap(const char *arg GCC_UNUSED,
			HTParentAnchor *anAnchor,
			HTFormat format_out,
			HTStream *sink)
{
    HTFormat format_in = WWW_HTML;
    HTStream *target;
    char *buf = 0;
    int i;

    /*
     * Set up the stream.  - FM
     */
    target = HTStreamStack(format_in, format_out, sink, anAnchor);
    if (!target || target == NULL) {
	HTSprintf0(&buf, CANNOT_CONVERT_I_TO_O,
		   HTAtom_name(format_in), HTAtom_name(format_out));
	HTAlert(buf);
	FREE(buf);
	return (HT_NOT_LOADED);
    }
    anAnchor->no_cache = TRUE;

    HTSprintf0(&buf, "<html>\n<head>\n<title>%s</title>\n</head>\n<body>\n",
	       CURRENT_KEYMAP_TITLE);
    PUTS(buf);
    HTSprintf0(&buf, "<pre>\n");
    PUTS(buf);
Пример #13
0
HTStream *HTCompressed( HTPresentation *pres, HTParentAnchor *anchor, HTStream *sink )
{
  int eax;
  HTStream *me;
  HTFormat format;
  char *type = 0;
  HTPresentation *Pres = 0;
  HTPresentation *Pnow = 0;
  int n, i;
  BOOLEAN can_present = 0;
  char fnam[256];
  char temp[256];
  char *suffix;
  char *uncompress_mask = 0;
  char *compress_suffix = "";
  char *middle;
  if ( anchor == 0 || anchor->content_encoding == 0 || anchor->content_type == 0 )
  {
    format = HTAtom_for( "application/octet-stream" );
    me = HTStreamStack( format, &pres->rep_out, &sink->isa->name[0], anchor );
    return me;
  }
  else
  {
    n = HTList_count( HTPresentations );
    i = 0;
    for ( ; i < n; i++ )
    {
      Pnow = (HTPresentation*)HTList_objectAt( HTPresentations, i );
      if ( strcasecomp( (char*)Pnow->rep_out, &anchor->content_type ) == 0 && Pnow->rep_out == HTAtom_for( "www/present" ) )
      {
        char *program = "";
        if ( Pres == 0 )
          Pres = Pnow;
        else
        if ( Pres->quality <= Pnow->quality )
          Pres = Pnow;
        can_present = 1;
        switch ( HTEncodingToCompressType( &anchor->content_encoding ) )
        {
        case 2:
          program = HTGetProgramPath( 6 );
          if ( program )
          {
            HTSACopy( &uncompress_mask, program );
            HTSACat( &uncompress_mask, " -d --no-name %s" );
            compress_suffix = "gz";
          }
          break;
        case 4:
          program = HTGetProgramPath( 7 );
          if ( program )
          {
            HTSACopy( &uncompress_mask, program );
            HTSACat( &uncompress_mask, " %s" );
            compress_suffix = "zz";
          }
          break;
        case 3:
          program = HTGetProgramPath( 1 );
          if ( program )
          {
            HTSACopy( &uncompress_mask, program );
            HTSACat( &uncompress_mask, " -d %s" );
            compress_suffix = "bz2";
          }
          break;
        case 1:
          program = HTGetProgramPath( 19 );
          if ( program )
          {
            HTSACopy( &uncompress_mask, program );
            HTSACat( &uncompress_mask, " %s" );
            compress_suffix = "Z";
          }
          break;
        }
      }
      // i++;
    }
    if ( can_present == 0 || uncompress_mask == 0 || strchr( &anchor->content_type, ';' ) || HTOutputFormat == HTAtom_for( "www/download" ) || !strcasecomp( &pres->rep_out->name, "www/download" ) || ( traversal && strcasecomp( &anchor->content_type, "text/html" ) && strcasecomp( &anchor->content_type, "text/plain" ) ) )
    {
      if ( strchr( &anchor->content_encoding, '/' ) == 0 )
      {
        if ( strncasecomp( &anchor->content_encoding, "x-", 2 ) == 0 )
          HTSACopy( &type, "application/" );
        else
          HTSACopy( &type, "application/x-" );
        HTSACat( &type, &anchor->content_encoding );
      }
      else
        HTSACopy( &type, &anchor->content_encoding );
      format = HTAtom_for( type );
      if ( type )
      {
        free( type );
        type = 0;
      }
      if ( uncompress_mask )
      {
        free( uncompress_mask );
        uncompress_mask = 0;
      }
      me = HTStreamStack( format, &pres->rep_out, &sink->isa->name[0], anchor );
      return me;
    }
    else
    {
      me = calloc( 1, sizeof( HTStream ) );
      if ( me == 0 )
        outofmem( "./HTFWriter.c", "HTCompressed" );
      me->isa->name[0] = HTFWriter.name;
      me->input_format = pres->rep->next;
      me->output_format = pres->rep_out;
      me->anchor = anchor;
      me->sink = sink;
      if ( anchor->FileCache )
      {
        LYRemoveTemp( &anchor->FileCache );
        if ( anchor->FileCache )
        {
          free( &anchor->FileCache );
          anchor->FileCache = 0;
        }
      }
      middle = 0;
      if ( strcasecomp( &anchor->content_type, "text/html" ) == 0 )
      {
        middle = ".html";
        middle++;
      }
      else
      {
        if ( strncasecomp( &anchor->content_type, "text/", 5 ) == 0 )
          middle = "txt";
        else
        {
          if ( strncasecomp( &anchor->content_type, "application/", 12 ) == 0 )
            middle = "bin";
          else
          {
            suffix = HTFileSuffix( HTAtom_for( &anchor->content_type ), 0 );
            if ( suffix && suffix[0] == '.' )
              middle = &suffix[1];
          }
        }
      }
      temp[0] = 0;
      if ( middle )
      {
        memcpy( temp[0] + strlen( temp ) );
        strcat( temp, middle );
        strcat( temp, "." );
      }
      strcat( temp, compress_suffix );
      me->fp = LYOpenTemp( fnam, temp, "wb" );
      if ( me->fp == 0 )
      {
        HTAlert( gettext( "Can't open temporary file!" ) );
        if ( uncompress_mask )
        {
          free( uncompress_mask );
          uncompress_mask = 0;
        }
        if ( me )
        {
          free( me );
          me = 0;
        }
        return 0;
      }
      else
      {
        if ( dump_output_immediately == 0 && traversal == 0 && ( Pres->quality < 999.000000000000 || ( no_exec == 0 && ( local_exec || ( local_exec_on_local_files && ( LYJumpFileURL || strncmp( &anchor->address, "file://localhost", 16 ) == 0 ) ) ) ) ) )
          HTSACopy( &me->viewer_command, &Pres->command );
        if ( compress_suffix[0] == 'g' && me->viewer_command == 0 )
          HTSACopy( &me->end_command, "" );
        else
        {
          *(int*)&me->end_command = 0;
          HTAddParam( &me->end_command, uncompress_mask, 1, fnam );
          HTEndParam( &me->end_command, uncompress_mask, 1 );
        }
        if ( uncompress_mask )
        {
          free( uncompress_mask );
          uncompress_mask = 0;
        }
        *(int*)&me->remove_command = 0;
        HTAddParam( &me->remove_command, "%s", 1, fnam );
        HTEndParam( &me->remove_command, "%s", 1 );
        HTSACopy( &anchor->FileCache, fnam );
        return me;
      }
    }
  }
}
Пример #14
0
PUBLIC int HTLoadHTTP ARGS4 (
	char *, 		arg,
	HTParentAnchor *,	anAnchor,
	HTFormat,		format_out,
	HTStream*,		sink)
{
  int s;				/* Socket number for returned data */
  char *command;			/* The whole command */
  char *eol;			/* End of line if found */
  char *start_of_data;		/* Start of body of reply */
  int status;				/* tcp return */
  int bytes_already_read;
  char crlf[3];			/* A CR LF equivalent string */
  HTStream *target;		/* Unconverted data */
  HTFormat format_in;			/* Format arriving in the message */

  char *line_buffer;
  char *line_kept_clean;
  BOOL extensions;		/* Assume good HTTP server */
  int compressed;
  char line[2048];	/* bumped up to cover Kerb huge headers */

  int length, doing_redirect, rv;
  int already_retrying = 0;
  int return_nothing;

  int i;
  int keepingalive = 0;
  char *p;

/*SWP*/
  int statusError=0;

  if (!arg)
    {
      status = -3;
      HTProgress ("Bad request.");
      goto done;
    }
  if (!*arg)
    {
      status = -2;
      HTProgress ("Bad request.");
      goto done;
    }

  sprintf(crlf, "%c%c", CR, LF);

  /* At this point, we're talking HTTP/1.0. */
  extensions = YES;

 try_again:
  /* All initializations are moved down here from up above,
     so we can start over here... */
  eol = 0;
  bytes_already_read = 0;
  length = 0;
  doing_redirect = 0;
  compressed = 0;
  target = NULL;
  line_buffer = NULL;
  line_kept_clean = NULL;
  return_nothing = 0;

	/* okay... addr looks like http://hagbard.ncsa.uiuc.edu/blah/etc.html
	lets crop it at the 3rd '/' */
	for(p = arg,i=0;*p && i!=3;p++)
		if(*p=='/') i++;

	if(i==3)
		i = p-arg; /* i = length not counting last '/' */
	else
		i = 0;

	if((lsocket != -1) && i && addr && !strncmp(addr,arg,i)){
		/* keepalive is active and addresses match -- try the old socket */
		s = lsocket;
		keepingalive = 1; /* flag in case of network error due to server timeout*/
		lsocket = -1; /* prevent looping on failure */
#ifndef DISABLE_TRACE
		if (www2Trace)
			fprintf (stderr,
				 "HTTP: Keep-Alive reusing '%s'\n",addr);
#endif
/*
		if (addr && *addr) {
			sprintf(tmpbuf,"Reusing socket from %s.",addr);
			HTProgress(tmpbuf);
		}
*/
	} else {
		if(addr) free(addr);
		/* save the address for next time around */
		addr = malloc(i+1);
		strncpy(addr,arg,i);
		*(addr+i)=0;

		keepingalive = 0; /* just normal opening of the socket */
		if(lsocket != -1) NETCLOSE(lsocket); /* no socket leaks here */
		lsocket = -1; /*dont assign until we know the server says okay */

#ifndef DISABLE_TRACE
		if (www2Trace)
			fprintf (stderr,
				 "HTTP: Keep-Alive saving '%s'\n",addr);
#endif
/*
		if (addr && *addr) {
			sprintf(tmpbuf,"Saving %s for possible socket reuse.",addr);
			HTProgress(tmpbuf);
		}
*/
	}

  if (!keepingalive) {
      status = HTDoConnect (arg, "HTTP", TCP_PORT, &s);
      if (status == HT_INTERRUPTED){
	  /* Interrupt cleanly. */
#ifndef DISABLE_TRACE
	  if (www2Trace)
	      fprintf (stderr,
		       "HTTP: Interrupted on connect; recovering cleanly.\n");
#endif
	  HTProgress ("Connection interrupted.");
	  /* status already == HT_INTERRUPTED */
	  goto done;
      }
      if (status < 0) {
#ifndef DISABLE_TRACE
	  if (www2Trace)
	      fprintf(stderr,
		      "HTTP: Unable to connect to remote host for `%s' (errno = %d).\n", arg, errno);
#endif
	  HTProgress ("Unable to connect to remote host.");
	  status = HT_NO_DATA;
	  goto done;
      }
  }
  /*	Ask that node for the document,
   **	omitting the host name & anchor
   */
  {
    char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION);
    command = malloc(5 + strlen(p1)+ 2 + 31);

    if (do_post && !do_put)
      strcpy(command, "POST ");
    else if (do_post && do_put)
      strcpy(command, "PUT ");
    else if (do_head)
      strcpy(command, "HEAD ");
    else if (do_meta)
      strcpy(command, "META ");
    else
      strcpy(command, "GET ");

    /*
     * For a gateway, the beginning '/' on the request must
     * be stripped before appending to the gateway address.
     */
    if ((using_gateway)||(using_proxy)) {
        strcat(command, p1+1);
    }
    else
        strcat(command, p1);
    free(p1);
  }
  if (extensions)
    {
      strcat(command, " ");
      strcat(command, HTTP_VERSION);
    }

  strcat(command, crlf);	/* CR LF, as in rfc 977 */

  if (extensions)
    {
#ifdef SAM_NOT_YET
		/* SAM This produces an absolutely huge Accept: line.  While
		   there is probably a better way to turn this off, just
		   compiling it out works for now.
		*/
      int n, i;

      if (!HTPresentations) HTFormatInit();
      n = HTList_count(HTPresentations);

      begin_ptr=command+strlen(command);
      env_length=0;

      sprintf(line, "Accept:");
      env_length+=strlen(line);
      StrAllocCat(command, line);

	/* KCMS Accept Header - swp */
	if (KCMS_Return_Format==JPEG) {
		sprintf(line," image/x-pcd-jpeg,");
		StrAllocCat(command, line);
		env_length+=strlen(line);
	}
	else if (KCMS_Return_Format==JYCC) {
		sprintf(line," image/x-pcd-jycc,");
		StrAllocCat(command, line);
		env_length+=strlen(line);
	}
	else if (KCMS_Return_Format==GIF) {
		sprintf(line," image/x-pcd-gif,");
		StrAllocCat(command, line);
		env_length+=strlen(line);
	}

      for(i=0; i<n; i++)
        {
          HTPresentation * pres = HTList_objectAt(HTPresentations, i);
          if (pres->rep_out == WWW_PRESENT)
            {
		sprintf(line, " %s,",HTAtom_name(pres->rep));
		env_length+=strlen(line);
		StrAllocCat(command, line);
		if (env_length>200) {
			if ((tmp_ptr=strrchr(command,','))!=NULL) {
				*tmp_ptr='\0';
			}
			sprintf(line, "%c%c",CR,LF);
			StrAllocCat(command, line);

			begin_ptr=command+strlen(command);
			sprintf(line, "Accept:");
			env_length=strlen(line);
			StrAllocCat(command, line);
		}
            }
        }

      /* This gets rid of the last comma. */
      if ((tmp_ptr=strrchr(command,','))!=NULL) {
	*tmp_ptr='\0';
	sprintf(line, "%c%c",CR,LF);
	StrAllocCat(command, line);
      }
      else { /* No accept stuff...get rid of "Accept:" */
	begin_ptr='\0';
      }
#endif

      /* if reloading, send no-cache pragma to proxy servers. --swp */
      /* original patch from Ari L. <*****@*****.**> */
      if (reloading) {
	sprintf(line, "Pragma: no-cache%c%c", CR, LF);
	StrAllocCat(command, line);
      }

      /*This is just used for "not" sending this header on a proxy request*/
      if (useKeepAlive) {
	sprintf(line, "Connection: keep-alive%c%c", CR, LF);
	StrAllocCat(command, line);
      }

      if (sendAgent) {
	sprintf(line, "User-Agent: %s%c%c",agent[selectedAgent],CR,LF);
/*
	sprintf(line, "User-Agent:  %s/%s  libwww/%s%c%c",
		HTAppName ? HTAppName : "unknown",
		HTAppVersion ? HTAppVersion : "0.0",
		HTLibraryVersion, CR, LF);
*/
	StrAllocCat(command, line);
      }

      if (sendReferer) {
	/* HTTP Referer field, specifies back-link URL   - amb */
	if (HTReferer) {
		sprintf(line, "Referer: %s%c%c", HTReferer, CR, LF);
		StrAllocCat(command, line);
		HTReferer = NULL;
	}
      }

      {
	char *tmp,*startPtr,*endPtr;

	/* addr is always in URL form */

	if (addr && !using_proxy && !using_gateway) {
		tmp=strdup(addr);
		startPtr=strchr(tmp,'/');
		if (startPtr) {
			startPtr+=2; /*now at begining of hostname*/
			if (*startPtr) {
				endPtr=strchr(startPtr,':');
				if (!endPtr) {
					endPtr=strchr(startPtr,'/');
					if (endPtr && *endPtr) {
						*endPtr='\0';
					}
				}
				else {
					*endPtr='\0';
				}

				sprintf(line, "Host: %s%c%c", startPtr, CR, LF);
				StrAllocCat(command, line);

				free(tmp);
				tmp=startPtr=endPtr=NULL;
			}
		}
	}
	else if (using_proxy || using_gateway) {
		sprintf(line, "Host: %s%c%c", proxy_host_fix, CR, LF);
		StrAllocCat(command, line);
	}
      }

      /* SWP -- 7/10/95 */
      /* HTTP Extension headers */
      /* Domain Restriction */
      sprintf(line,"Extension: Notify-Domain-Restriction%c%c",CR,LF);
      StrAllocCat(command,line);

      /* BJS -- 12/05/95 -- allow arbitrary headers sent from browser */
      if(extra_headers){
		int h;
		for(h=0;extra_headers[h];h++){
			sprintf(line,"%s%c%c",extra_headers[h],CR,LF);
			StrAllocCat(command,line);
		}
      }

      {
        char *docname;
        char *hostname;
        char *colon;
        int portnumber;
        char *auth;

        docname = HTParse(arg, "", PARSE_PATH);
        hostname = HTParse(arg, "", PARSE_HOST);
        if (hostname &&
            NULL != (colon = strchr(hostname, ':')))
          {
            *(colon++) = '\0';	/* Chop off port number */
            portnumber = atoi(colon);
          }
        else portnumber = 80;

        if (NULL!=(auth=HTAA_composeAuth(hostname, portnumber, docname)))
          {
            sprintf(line, "%s%c%c", auth, CR, LF);
            StrAllocCat(command, line);
          }
#ifndef DISABLE_TRACE
        if (www2Trace)
          {
            if (auth)
              fprintf(stderr, "HTTP: Sending authorization: %s\n", auth);
            else
              fprintf(stderr, "HTTP: Not sending authorization (yet)\n");
          }
#endif
        FREE(hostname);
        FREE(docname);
      }
    }

  if (do_post && !do_put)
    {
#ifndef DISABLE_TRACE
      if (www2Trace)
        fprintf (stderr, "HTTP: Doing post, content-type '%s'\n",
                 post_content_type);
#endif
      sprintf (line, "Content-type: %s%c%c",
               post_content_type ? post_content_type : "lose", CR, LF);
      StrAllocCat(command, line);
      {
        int content_length;
        if (!post_data)
          content_length = 4; /* 4 == "lose" :-) */
        else
          content_length = strlen (post_data);
        sprintf (line, "Content-length: %d%c%c",
                 content_length, CR, LF);
        StrAllocCat(command, line);
      }

      StrAllocCat(command, crlf);	/* Blank line means "end" */

      if (post_data)
        StrAllocCat(command, post_data);
      else
        StrAllocCat(command, "lose");
    }
  else if (do_post && do_put)
    {
      sprintf (line, "Content-length: %d%c%c",
	       put_file_size, CR, LF);
      StrAllocCat(command, line);
      StrAllocCat(command, crlf);	/* Blank line means "end" */
    }
  else {
      StrAllocCat(command, crlf);	/* Blank line means "end" */
  }

#ifndef DISABLE_TRACE
  if (www2Trace)
    fprintf (stderr, "Writing:\n%s----------------------------------\n",
             command);
#endif

/*
  HTProgress ("Sending HTTP request.");
*/

  status = NETWRITE(s, command, (int)strlen(command));
  if (do_post && do_put) {
      char buf[BUFSIZ];
      int upcnt=0,n;

      while (status>0) {
	n=fread(buf,1,BUFSIZ-1,put_fp);

	upcnt+= status = NETWRITE(s, buf, n);
#ifndef DISABLE_TRACE
	if (www2Trace) {
		fprintf(stderr,"[%d](%d) %s",status,n,buf);
	}
#endif
	if (feof(put_fp)) {
		break;
	}
      }

      if (status<0 || !feof(put_fp) || upcnt!=put_file_size) {
	char tmpbuf[BUFSIZ];

	sprintf(tmpbuf,"Status: %d  --  EOF: %d  --  UpCnt/FileSize: %d/%d\n\nThe server you connected to either does not support\nthe PUT method, or an error occurred.\n\nYour upload was corrupted! Please try again!",status,(feof(put_fp)?1:0),upcnt,put_file_size);
	application_error(tmpbuf,"Upload Error!");
      }
  }

  /* Twirl on each request to make things look nicer -- SWP */
  HTCheckActiveIcon(1);

#ifndef DISABLE_TRACE
  if (httpTrace) {
	fprintf(stderr,"%s",command);
  }
#endif

  free (command);
  if (status <= 0)
    {
      if (status == 0)
        {
#ifndef DISABLE_TRACE
          if (www2Trace)
            fprintf (stderr, "HTTP: Got status 0 in initial write\n");
#endif
          /* Do nothing. */
        }
      else if
        ((errno == ENOTCONN || errno == ECONNRESET || errno == EPIPE) &&
         !already_retrying &&
         /* Don't retry if we're posting. */ !do_post)
          {
            /* Arrrrgh, HTTP 0/1 compability problem, maybe. */
#ifndef DISABLE_TRACE
            if (www2Trace)
              fprintf
                (stderr,
                 "HTTP: BONZO ON WRITE Trying again with HTTP0 request.\n");
#endif
/*
            HTProgress ("Retrying as HTTP0 request.");
*/
            NETCLOSE(s);
// SAM            extensions = NO;
            already_retrying = 1;
            goto try_again;
          }
      else
        {
		if(keepingalive){
#ifndef DISABLE_TRACE
			if (www2Trace)
				fprintf (stderr, "HTTP: Timeout on Keep-Alive. Retrying.\n");
#endif
			HTProgress("Server Timeout: Reconnecting");
			goto try_again;
		}
#ifndef DISABLE_TRACE
          if (www2Trace)
            fprintf (stderr, "HTTP: Hit unexpected network WRITE error; aborting connection.\n");
#endif
          NETCLOSE (s);
          status = -1;
          HTProgress ("Unexpected network write error; connection aborted.");
          goto done;
        }
    }

#ifndef DISABLE_TRACE
  if (www2Trace)
    fprintf (stderr, "HTTP: WRITE delivered OK\n");
#endif
  HTProgress ("Done sending HTTP request; waiting for response.");

  /*	Read the first line of the response
   **	-----------------------------------
   */

  {
      /* Get numeric status etc */
      BOOL end_of_file = NO;
      int buffer_length = INIT_LINE_SIZE;

      line_buffer = (char *) malloc(buffer_length * sizeof(char));

      do {
	  /* Loop to read in the first line */
	  /* Extend line buffer if necessary for those crazy WAIS URLs ;-) */
	  if (buffer_length - length < LINE_EXTEND_THRESH) {
	      buffer_length = buffer_length + buffer_length;
	      line_buffer =
		  (char *) realloc(line_buffer, buffer_length * sizeof(char));
          }
#ifndef DISABLE_TRACE
	  if (www2Trace)
	      fprintf (stderr, "HTTP: Trying to read %d\n",
		       buffer_length - length - 1);
#endif
	  status = NETREAD(s, line_buffer + length,
			   buffer_length - length - 1);
#ifndef DISABLE_TRACE
	  if (www2Trace)
	      fprintf (stderr, "HTTP: Read %d\n", status);
#endif
	  if (status <= 0) {
	      /* Retry if we get nothing back too;
		 bomb out if we get nothing twice. */
	      if (status == HT_INTERRUPTED) {
#ifndef DISABLE_TRACE
		  if (www2Trace)
		      fprintf (stderr, "HTTP: Interrupted initial read.\n");
#endif
		  HTProgress ("Connection interrupted.");
		  status = HT_INTERRUPTED;
		  NETCLOSE (s);
		  goto clean_up;
              } else
		  if
		  (status < 0 &&
		   (errno == ENOTCONN || errno == ECONNRESET || errno == EPIPE)
		   && !already_retrying && !do_post)
		      {
			  /* Arrrrgh, HTTP 0/1 compability problem, maybe. */
#ifndef DISABLE_TRACE
			  if (www2Trace)
			      fprintf (stderr, "HTTP: BONZO Trying again with HTTP0 request.\n");
#endif
			  NETCLOSE(s);
			  if (line_buffer)
			      free(line_buffer);
			  if (line_kept_clean)
			      free(line_kept_clean);

			  extensions = NO;
			  already_retrying = 1;
			  HTProgress ("Retrying as HTTP0 request.");
			  goto try_again;
		      } else {
			      if(keepingalive){
#ifndef DISABLE_TRACE
					if (www2Trace)
						fprintf (stderr, "HTTP: Timeout on Keep-Alive. Retrying.\n");
#endif
					HTProgress("Server Timeout: Reconnecting");
					goto try_again;
			      }
#ifndef DISABLE_TRACE
			  if (www2Trace)
			      fprintf (stderr, "HTTP: Hit unexpected network read error; aborting connection; status %d.\n", status);
#endif
			  HTProgress
			      ("Unexpected network read error; connection aborted.");

			  NETCLOSE (s);
			  status = -1;
			  goto clean_up;
		      }
          }

	  bytes_already_read += status;
	  {
	      char line[256];
	      sprintf (line, "Read %d bytes of data.", bytes_already_read);
	      HTProgress (line);
	  }

	  if (status == 0) {
	      end_of_file = YES;
	      break;
          }
	  line_buffer[length+status] = 0;

	  if (line_buffer) {
	      if (line_kept_clean)
		  free (line_kept_clean);
	      line_kept_clean = (char *)malloc (buffer_length * sizeof (char));
/*
	      bcopy (line_buffer, line_kept_clean, buffer_length);
*/
	      memcpy (line_kept_clean, line_buffer, buffer_length);
          }

	  eol = strchr(line_buffer + length, LF);
	  /* Do we *really* want to do this? */
	  if (eol && eol != line_buffer && *(eol-1) == CR)
	      *(eol-1) = ' ';

	  length = length + status;

	  /* Do we really want to do *this*? */
	  if (eol)
	      *eol = 0;		/* Terminate the line */
      /* All we need is the first line of the response.  If it's a HTTP/1.0
	 response, then the first line will be absurdly short and therefore
	 we can safely gate the number of bytes read through this code
	 (as opposed to below) to ~1000. */
      /* Well, let's try 100. */
      } while (!eol && !end_of_file && bytes_already_read < 100);
  } /* Scope of loop variables */


  /*	We now have a terminated unfolded line. Parse it.
   **	-------------------------------------------------
   */
#ifndef DISABLE_TRACE
  if (www2Trace)
    fprintf(stderr, "HTTP: Rx: %s\n", line_buffer);
#endif

  {
    int fields;
    char server_version[VERSION_LENGTH+1];
    int server_status;

	/*SWP*/
	statusError=0;

    server_version[0] = 0;

    fields = sscanf(line_buffer, "%20s %d",
                    server_version,
                    &server_status);

#ifndef DISABLE_TRACE
    if (www2Trace)
      fprintf (stderr, "HTTP: Scanned %d fields from line_buffer\n", fields);
#endif
#ifndef DISABLE_TRACE
    if (www2Trace)
      fprintf (stderr, "HTTP: line_buffer '%s'\n", line_buffer);
#endif

    /* Rule out HTTP/1.0 reply as best we can. */
    if (fields < 2 || !server_version[0] || server_version[0] != 'H' ||
        server_version[1] != 'T' || server_version[2] != 'T' ||
        server_version[3] != 'P' || server_version[4] != '/' ||
        server_version[6] != '.')
      {
        /* HTTP0 reply */
        HTAtom * encoding;

#ifndef DISABLE_TRACE
        if (www2Trace)
          fprintf (stderr, "--- Talking HTTP0.\n");
#endif

        format_in = HTFileFormat(arg, &encoding, WWW_HTML, &compressed);
        start_of_data = line_kept_clean;
      }
    else
      {
        /* Decode full HTTP response */
        format_in = HTAtom_for("www/mime");
        /* We set start_of_data to "" when !eol here because there
           will be a put_block done below; we do *not* use the value
           of start_of_data (as a pointer) in the computation of
           length or anything else in this situation. */
        start_of_data = eol ? eol + 1 : "";
        length = eol ? length - (start_of_data - line_buffer) : 0;

#ifndef DISABLE_TRACE
        if (www2Trace)
          fprintf (stderr, "--- Talking HTTP1.\n");
#endif

        switch (server_status / 100)
          {
          case 3:		/* Various forms of redirection */
            /* We now support this in the parser, at least. */
            doing_redirect = 1;
            break;

          case 4:		/* "I think I goofed" */
            switch (server_status)
              {
              case 403:
		statusError=1;
                /* 403 is "forbidden"; display returned text. */
                break;

              case 401:
                /* length -= start_of_data - text_buffer; */
                if (HTAA_shouldRetryWithAuth(start_of_data, length, s))
                  {
                    (void)NETCLOSE(s);
			lsocket = -1;
                    if (line_buffer)
                      free(line_buffer);
                    if (line_kept_clean)
                      free(line_kept_clean);

#ifndef DISABLE_TRACE
                    if (www2Trace)
                      fprintf(stderr, "%s %d %s\n",
                              "HTTP: close socket", s,
                              "to retry with Access Authorization");
#endif

                    HTProgress ("Retrying with access authorization information.");
                    goto try_again;
                    break;
                  }
                else
                  {
		    statusError=1;
                    /* Fall through. */
                  }

              default:
		statusError=1;
                break;
              } /* case 4 switch */
            break;

          case 5:		/* I think you goofed */
	    statusError=1;
            break;

          case 2:		/* Good: Got MIME object */
            switch (server_status)
              {
              case 204:
                return_nothing = 1;
                format_in = HTAtom_for("text/html");
                break;
	      case 200:
		if (do_head) {
			if (!start_of_data || !*start_of_data) {
				headData=NULL;
			}
			else {
				char *ptr;

				headData=strdup(start_of_data);
				ptr=strchr(headData,'\n');
				*ptr='\0';
			}
		}
		break;
              default:
                break;
              }
            break;

          default:		/* bad number */
	    statusError=1;
            HTAlert("Unknown status reply from server!");
            break;
          } /* Switch on server_status/100 */

      }	/* Full HTTP reply */
  } /* scope of fields */

  /* Set up the stream stack to handle the body of the message */
  target = HTStreamStack(format_in,
                         format_out,
                         compressed,
                         sink, anAnchor);

  if (!target)
    {
      char buffer[1024];	/* @@@@@@@@ */
      sprintf(buffer, "Sorry, no known way of converting %s to %s.",
              HTAtom_name(format_in), HTAtom_name(format_out));
      HTProgress (buffer);
      status = -1;
      NETCLOSE (s);
	lsocket = -1;
      goto clean_up;
    }

  if (!return_nothing)
    {
#ifndef DISABLE_TRACE
      if (www2Trace)
        fprintf (stderr, "HTTP: Doing put_block, '%s'\n", start_of_data);
#endif
/* BJS: parse start_of_data...*/
	for(p=start_of_data;*p;p++){
/*		if(*p=='C' && !strncmp("Content-length: ",p,16)){
		i = 0;
		p+=16;
		while(*p && isdigit(*p)){
			i = i*10 + *p-'0';
			p++;
		}
		p--;
#ifndef DISABLE_TRACE
		if(www2Trace)
			fprintf(stderr, "HTTP: Content Length is %d\n",i);
#endif
	}
*/
		if(*p=='K' && !strncmp("Keep-Alive:",p,11)){
#ifndef DISABLE_TRACE
			if (www2Trace)
				fprintf (stderr, "HTTP: Server Agrees to Keep-Alive\n");
#endif
			lsocket = s;
			p+=10;
		}
	}

#ifndef DISABLE_TRACE
        if (www2Trace && lsocket == -1)
		fprintf (stderr, "HTTP: Server does not agree to Keep-Alive\n");
#endif
      /* Recycle the first chunk of data, in all cases. */
      (*target->isa->put_block)(target, start_of_data, length);

      /* Go pull the bulk of the data down. */
	/* if we dont use length, header length is wrong due to the
	    discarded first line - bjs*/
      rv = HTCopy(s, target, length /*bytes_already_read*/);
      if (rv == -1)
        {
          (*target->isa->handle_interrupt) (target);
          status = HT_INTERRUPTED;
	  NETCLOSE (s);
		lsocket = -1;
          goto clean_up;
        }
      if (rv == -2 && !already_retrying && !do_post)
        {
          /* Aw hell. */
#ifndef DISABLE_TRACE
          if (www2Trace)
            fprintf (stderr, "HTTP: Trying again with HTTP0 request.\n");
#endif
          /* May as well consider it an interrupt -- right? */
          (*target->isa->handle_interrupt) (target);
          NETCLOSE(s);
          if (line_buffer)
            free(line_buffer);
          if (line_kept_clean)
            free(line_kept_clean);

          extensions = NO;
          already_retrying = 1;
          HTProgress ("Retrying as HTTP0 request.");
          goto try_again;
        }
    }
  else
    {
      /* return_nothing is high. */
      (*target->isa->put_string) (target, "<mosaic-access-override>\n");
      HTProgress ("And silence filled the night.");
    }

  (*target->isa->end_document)(target);

  /* Close socket before doing free. */
	if(lsocket == -1){
		NETCLOSE(s);
#ifndef DISABLE_TRACE
		if(www2Trace)
			fprintf(stderr,"HTTP: Closing connection\n");
#endif
	} else {
		HTProgress("Leaving Server Connection Open");
#ifndef DISABLE_TRACE
		if(www2Trace)
			fprintf(stderr,"HTTP: Keeping connection alive\n");
#endif
	}
/*
  else {
      NETCLOSE(s);
#ifndef DISABLE_TRACE
      if(www2Trace)
	fprintf(stderr,"HTTP: Closing connection\n");
#endif
  }
*/

  (*target->isa->free)(target);

  if (doing_redirect)
    {
      /* OK, now we've got the redirection URL temporarily stored
         in external variable redirecting_url, exported from HTMIME.c,
         since there's no straightforward way to do this in the library
         currently.  Do the right thing. */
      status = HT_REDIRECTING;
    }
  else
    {
      status = HT_LOADED;
    }

  /*	Clean up
   */

 clean_up:
  if (line_buffer)
    free(line_buffer);
  if (line_kept_clean)
    free(line_kept_clean);

 done:
  /* Clear out on exit, just in case. */
  do_post = 0;

  if (statusError) {
	securityType=HTAA_NONE;
#ifndef DISABLE_TRACE
	if (www2Trace)
		fprintf(stderr,"Resetting security type to NONE.\n");
#endif
  }

  return status;
}
Пример #15
0
PRIVATE int FileEvent (SOCKET soc, void * pVoid, HTEventType type)
{
    file_info *file = pVoid;			      /* Specific access information */
    int status = HT_ERROR;
    HTNet * net = file->net;
    HTRequest * request = HTNet_request(net);
    HTParentAnchor * anchor = HTRequest_anchor(request);

    /*
    ** Initiate a new file structure and bind to request structure
    ** This is actually state FILE_BEGIN, but it can't be in the state
    ** machine as we need the structure first.
    */
    if (type == HTEvent_CLOSE) {				      /* Interrupted */
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
			   NULL, 0, "HTLoadFile");
	FileCleanup(request, HT_INTERRUPTED);
	return HT_OK;
    }


    /* Now jump into the machine. We know the state from the previous run */
    while (1) {
	switch (file->state) {
	case FS_BEGIN:

	    /* We only support safe (GET, HEAD, etc) methods for the moment */
	    if (!HTMethod_isSafe(HTRequest_method(request))) {
		HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
				   NULL, 0, "HTLoadFile");
		file->state = FS_ERROR;
		break;
	    }

	    /* Check whether we have access to local disk at all */
	    if (HTLib_secure()) {
		HTTRACE(PROT_TRACE, "LoadFile.... No access to local file system\n");
		file->state = FS_TRY_FTP;
		break;
	    }
	    file->local = HTWWWToLocal(HTAnchor_physical(anchor), "",
				       HTRequest_userProfile(request));
	    if (!file->local) {
		file->state = FS_TRY_FTP;
		break;
	    }

	    /* Create a new host object and link it to the net object */
	    {
		HTHost * host = NULL;
		if ((host = HTHost_new("localhost", 0)) == NULL) return HT_ERROR;
		HTNet_setHost(net, host);
		if (HTHost_addNet(host, net) == HT_PENDING) {
		    HTTRACE(PROT_TRACE, "HTLoadFile.. Pending...\n");
		    /* move to the hack state */
		    file->state = FS_PENDING;
		    return HT_OK;
		}
	    }
	    file->state = FS_DO_CN;
	    break;

	case FS_PENDING:
	    /*
	    ** 2000/08/10 JK : This is a funny state. Because of the
	    ** internal libwww stacks, when doing multiple local
	    ** requests (e.g., while using the Robot), we need to ask
	    ** again for the host object. If we had jumped directly to
	    ** the FS_DO_CN state, libwww would have blocked because
	    ** of socket starvation.
	    ** This state is similar to FS_BEGINNING, but just requests 
	    ** the host object. 
	    ** YES. THIS IS AN UGLY HACK!!
	    */
	    {
		HTHost * host = NULL;
		if ((host = HTHost_new("localhost", 0)) == NULL) return HT_ERROR;
		HTNet_setHost(net, host);
		if (HTHost_addNet(host, net) == HT_PENDING) {
		    HTTRACE(PROT_TRACE, "HTLoadFile.. Pending...\n");
		    file->state = FS_PENDING;
		    return HT_OK;
		}
	    }
	    file->state = FS_DO_CN;
	    break;

	case FS_DO_CN:
	    /*
	    ** If we have to do content negotiation then find the object that
	    ** fits best into either what the client has indicated in the
	    ** accept headers or what the client has registered on its own.
	    ** The object chosen can in fact be a directory! However, content
	    ** negotiation only makes sense if we can read the directory!
	    ** We stat the file in order to find the size and to see it if
	    ** exists.
	    */
	    if (HTRequest_negotiation(request) &&
		HTMethod_isSafe(HTRequest_method(request))) {
 		char * conneg = HTMulti(request, file->local,&file->stat_info);
		if (conneg) {
		    HT_FREE(file->local);
		    file->local = conneg;
		    HTAnchor_setPhysical(anchor, conneg);
		    HTTRACE(PROT_TRACE, "Load File... Found `%s\'\n" _ conneg);
		} else {
		    HTTRACE(PROT_TRACE, "Load File... Not found - even tried content negotiation\n");
		    HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_ERROR;
		    break;
		}
	    } else {
		if (HT_STAT(file->local, &file->stat_info) == -1) {
		    HTTRACE(PROT_TRACE, "Load File... Not found `%s\'\n" _ file->local);
		    HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_ERROR;
		    break;
		}
	    }

	    /*
	    ** Check to see if the 'localname' is in fact a directory.
	    ** Note that we can't do a HEAD on a directory
	    */
	    if (((file->stat_info.st_mode) & S_IFMT) == S_IFDIR) {
		if (HTRequest_method(request) == METHOD_GET)
		    file->state = FS_PARSE_DIR;
		else {
		    HTRequest_addError(request, ERR_INFO, NO, HTERR_NO_CONTENT,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_NO_DATA;
		}
		break;
	    }

	    /*
	    ** If empty file then only serve it if it is editable. We also get
	    ** the bindings for the file suffixes in lack of better bindings
	    */
	    {
		BOOL editable = HTEditable(file->local, &file->stat_info);
		if (file_suffix_binding) HTBind_getAnchorBindings(anchor);
		if (editable) HTAnchor_appendAllow(anchor, METHOD_PUT);

		/* Set the file size */
		if (file->stat_info.st_size)
		    HTAnchor_setLength(anchor, file->stat_info.st_size);

		/* Set the file last modified time stamp */
		if (file->stat_info.st_mtime > 0)
		    HTAnchor_setLastModified(anchor, file->stat_info.st_mtime);

		/* Check to see if we can edit it */
		if (!editable && !file->stat_info.st_size) {
		    HTRequest_addError(request, ERR_INFO, NO, HTERR_NO_CONTENT,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_NO_DATA;
		} else {
		    file->state = (HTRequest_method(request)==METHOD_GET) ? 
			FS_NEED_OPEN_FILE : FS_GOT_DATA;
		}
	    }
	    break;

	  case FS_NEED_OPEN_FILE:
	    status = HTFileOpen(net, file->local, HT_FB_RDONLY);
	    if (status == HT_OK) {
		/* 
		** Create the stream pipe FROM the channel to the application.
		** The target for the input stream pipe is set up using the
		** stream stack.
		*/
		{
		    HTStream * rstream = HTStreamStack(HTAnchor_format(anchor),
						       HTRequest_outputFormat(request),
						       HTRequest_outputStream(request),
						       request, YES);
		    HTNet_setReadStream(net, rstream);
		    HTRequest_setOutputConnected(request, YES);
		}

		/*
		** Create the stream pipe TO the channel from the application
		** and hook it up to the request object
		*/
		{
		    HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
		    HTRequest_setInputStream(request, (HTStream *) output);
		}

		/*
		** Set up concurrent read/write if this request isn't the
		** source for a PUT or POST. As source we don't start reading
		** before all destinations are ready. If destination then
		** register the input stream and get ready for read
		*/
		if (HTRequest_isSource(request) && !HTRequest_destinationsReady(request))
		    return HT_OK;
		HTRequest_addError(request, ERR_INFO, NO, HTERR_OK, NULL, 0,
				   "HTLoadFile");
		file->state = FS_NEED_BODY;

		/* If we are _not_ using preemptive mode and we are Unix fd's
		** then return here to get the same effect as when we are
		** connecting to a socket. That way, HTFile acts just like any
		** other protocol module even though we are in fact doing
		** blocking connect
		*/
		if (HTEvent_isCallbacksRegistered()) {
		    if (!HTRequest_preemptive(request)) {
			if (!HTNet_preemptive(net)) {
			    HTTRACE(PROT_TRACE, "HTLoadFile.. Returning\n");
			    HTHost_register(HTNet_host(net), net, HTEvent_READ);
			} else if (!file->timer) {
			    HTTRACE(PROT_TRACE, "HTLoadFile.. Returning\n");
			    file->timer =
				HTTimer_new(NULL, ReturnEvent, file, 1, YES, NO);
			}
			return HT_OK;
		    }
		}
	    } else if (status == HT_WOULD_BLOCK || status == HT_PENDING)
		return HT_OK;
	    else {
		HTRequest_addError(request, ERR_INFO, NO, HTERR_INTERNAL,
				   NULL, 0, "HTLoadFile");
		file->state = FS_ERROR;		       /* Error or interrupt */
	    }
	    break;

	  case FS_NEED_BODY:
	    status = HTHost_read(HTNet_host(net), net);
	    if (status == HT_WOULD_BLOCK)
		return HT_OK;
	    else if (status == HT_LOADED || status == HT_CLOSED) {
		file->state = FS_GOT_DATA;
	    } else {
		HTRequest_addError(request, ERR_INFO, NO, HTERR_FORBIDDEN,
				   NULL, 0, "HTLoadFile");
		file->state = FS_ERROR;
	    }
	    break;

	  case FS_PARSE_DIR:
	    status = HTFile_readDir(request, file);
	    if (status == HT_LOADED)
		file->state = FS_GOT_DATA;
	    else
		file->state = FS_ERROR;
	    break;

	  case FS_TRY_FTP:
	    {
		char *url = HTAnchor_physical(anchor);
		HTAnchor *anchor;
		char *newname = NULL;
		StrAllocCopy(newname, "ftp:");
		if (!strncmp(url, "file:", 5))
		    StrAllocCat(newname, url+5);
		else
		    StrAllocCat(newname, url);
		anchor = HTAnchor_findAddress(newname);
		HTRequest_setAnchor(request, anchor);
		HT_FREE(newname);
		FileCleanup(request, HT_IGNORE);
		return HTLoad(request, YES);
	    }
	    break;

	  case FS_GOT_DATA:
	    FileCleanup(request, HT_LOADED);
	    return HT_OK;
	    break;

	  case FS_NO_DATA:
	    FileCleanup(request, HT_NO_DATA);
	    return HT_OK;
	    break;

	  case FS_RETRY:
	    FileCleanup(request, HT_RETRY);
	    return HT_OK;
	    break;

	  case FS_ERROR:
	    FileCleanup(request, HT_ERROR);
	    return HT_OK;
	    break;
	}
    } /* End of while(1) */
}
Пример #16
0
PRIVATE int HTGuess_flush (HTStream * me)
{
    if (!me->transparent) {
	HTResponse * response = me->response;

	/*
	**  First we look for magic tokens and evaluate the contents of the buffer
	**  that we are investigating. 
	*/
	if (me->cnt) {
	    HTTRACE(STREAM_TRACE, "GUESSING.... Result of content analysis: Text=%d%% Newlines=%d%% Ctrl=%d%% High=%d%%\n" _ 
			(int)(100*me->text_cnt/me->cnt + 0.5) _ 
			(int)(100*me->lf_cnt  /me->cnt + 0.5) _ 
			(int)(100*me->ctrl_cnt/me->cnt + 0.5) _ 
			(int)(100*me->high_cnt/me->cnt + 0.5));
	}
	
	if (!me->ctrl_cnt ||
	    me->text_cnt + me->lf_cnt >= 16 * (me->ctrl_cnt + me->high_cnt)) {
	    char *ptr;
	    /* some kind of text */
	    
	    *me->write_ptr = 0;	/* terminate buffer */
	    
	    if (me->high_cnt > 0)
		HTResponse_setContentTransferEncoding(response, WWW_CODING_8BIT);
	    else
		HTResponse_setContentTransferEncoding(response, WWW_CODING_7BIT);
	    
	    if (is_html(me->buffer))
		HTResponse_setFormat(response, HTAtom_for("text/html"));
	    
	    else if (!strncmp(me->buffer, "%!", 2))
		HTResponse_setFormat(response, HTAtom_for("application/postscript"));
	    
	    else if (strstr(me->buffer, "#define") &&
		     strstr(me->buffer, "_width") &&
		     strstr(me->buffer, "_bits"))
		HTResponse_setFormat(response, HTAtom_for("image/x-xbitmap"));
	    
	    else if ((ptr = strstr(me->buffer, "converted with BinHex"))!=NULL)
		HTResponse_setContentTransferEncoding(response, WWW_CODING_MACBINHEX);

	    else if (!strncmp(me->buffer, "begin ", 6))
		HTResponse_setContentTransferEncoding(response, WWW_CODING_BASE64);

	    else
		HTResponse_setFormat(response, WWW_PLAINTEXT);
	}
	else {
	    if (!strncmp(me->buffer, "GIF", 3))
		HTResponse_setFormat(response, WWW_GIF);

	    else if (!strncmp(me->buffer, "\377\330\377\340", 4))
		HTResponse_setFormat(response, WWW_JPEG);

	    else if (!strcmp(me->buffer, "MM"))	/* MM followed by a zero */
		HTResponse_setFormat(response, WWW_TIFF);

 	    else if (!strncmp(me->buffer, "\211PNG\r\n\032\n", 8))
 		HTResponse_setFormat(response, WWW_PNG);

	    else if (!strncmp(me->buffer, ".snd", 4))
		HTResponse_setFormat(response, WWW_AUDIO);

	    else if (!strncmp(me->buffer, "\037\235", 2))
		HTResponse_addEncoding(response, WWW_CODING_COMPRESS);

	    else if (!strncmp(me->buffer, "\037\213", 2))
		HTResponse_addEncoding(response, WWW_CODING_GZIP);

	    else
		HTResponse_setFormat(response, WWW_BINARY);
	}
	
	/*
	**  If we couldn't find any magic tokens then we try and look at the suffix
	**  of the URL file name and use our own bindings to see if that gives any
	**  results.
	*/
	if (HTResponse_format(response) == WWW_UNKNOWN) {
	    HTParentAnchor * anchor = HTRequest_anchor(me->request);
	    char * addr = HTAnchor_physical(anchor);
	    HTTRACE(STREAM_TRACE, "GUESSING.... Hmm - trying local bindings\n");
	    HTBind_getResponseBindings (response, addr);
	}

	/*
	**  If nothing worked then give up and say binary...
	*/
	if (HTResponse_format(response) == WWW_UNKNOWN) {
	    HTTRACE(STREAM_TRACE, "GUESSING.... That's it - I'm giving up!\n");
	    HTResponse_setFormat(response, WWW_BINARY);
	}
		
	HTTRACE(STREAM_TRACE, "Guessed..... Content-Type `%s\'\n" _ HTAtom_name(HTResponse_format(response)));

	/*
	**  Set up the new stream stack with the type we figured out 
	*/
	if ((me->target = HTStreamStack(HTResponse_format(response),
					me->output_format, me->output_stream,
					me->request, NO)) == NULL) {
	    HTTRACE(STREAM_TRACE, "HTGuess..... Can't convert media type\n");
	    me->target = HTErrorStream();
	}
	me->transparent = YES;
	return PUT_BLOCK(me->buffer, me->cnt);
    }
    return HT_OK;
}
Пример #17
0
PRIVATE int SocketEvent (SOCKET soc, void * pVoid, HTEventType type)
{
    raw_info * raw = (raw_info *) pVoid;
    int status = HT_ERROR;
    HTNet * net = raw->net;
    HTRequest * request = raw->request;
    HTHost * host = HTNet_host(net);

    /*
    **  Check whether we have been interrupted or timed out
    */
    if (type == HTEvent_BEGIN) {
	raw->state = RAW_BEGIN;
    } else if (type == HTEvent_CLOSE) {			      /* Interrupted */
	RawCleanup(request, HT_INTERRUPTED);
	return HT_OK;
    } else if (type == HTEvent_TIMEOUT) {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_TIME_OUT,
			   NULL, 0, "HTLoadSocket");
	RawCleanup(request, HT_TIMEOUT);
	return HT_OK;
    } else if (type == HTEvent_END) {
	RawCleanup(request, HT_OK);
	return HT_OK;
    }
	
    /* Now jump into the state machine */
    while (1) {
	switch(raw->state) {
	case RAW_BEGIN:
	    status = HTHost_accept(host, net, NULL);
	    host = HTNet_host(net);
            if (status == HT_OK) {
		raw->state = RAW_NEED_STREAM;
	    } else if (status == HT_WOULD_BLOCK || status == HT_PENDING) {
		return HT_OK;
	    } else	
		raw->state = RAW_ERROR;	       /* Error or interrupt */
	    break;

	case RAW_NEED_STREAM:
	{
	    /* 
	    ** Create the stream pipe FROM the channel to the application.
	    ** The target for the input stream pipe is set up using the
	    ** stream stack.
	    */
            HTStream * in_stream =
		HTStreamStack(WWW_RAW,
			      HTRequest_outputFormat(request),
			      HTRequest_outputStream(request),
			      request, YES);
	    HTNet_setReadStream(net, in_stream);
            HTRequest_setOutputConnected(request, YES);

	    raw->state = RAW_READ;
	    break;
	}

	case RAW_READ:
	    status = HTHost_read(host, net);
	    if (status == HT_WOULD_BLOCK)
		return HT_OK;
	    else if (status==HT_CLOSED)
		raw->state = RAW_OK;
	    else 
		raw->state = RAW_ERROR;
	    break;

	case RAW_OK:
	    RawCleanup(request, HT_OK);
	    return HT_OK;
	    break;

	case RAW_ERROR:
	    RawCleanup(request, HT_ERROR);
	    return HT_OK;
	    break;

	default:
	    HTDEBUGBREAK("Bad raw state %d\n" _ raw->state);
	}
    }
    return HT_OK;
}
Пример #18
0
/*	Partial Response MIME parser stream
**	-----------------------------------
**	In case we sent a Range conditional GET we may get back a partial
**	response. This response must be appended to the already existing
**	cache entry before presented to the user.
**	We do this by continuing to load the new object into a temporary 
**	buffer and at the same time start the cache load of the already
**	existing object. When we have loaded the cache we merge the two
**	buffers.
*/
PUBLIC HTStream * HTMIMEPartial (HTRequest *	request,
				 void *		param,
				 HTFormat	input_format,
				 HTFormat	output_format,
				 HTStream *	output_stream)
{
#ifndef NO_CACHE
    HTParentAnchor * anchor = HTRequest_anchor(request);
    HTFormat format = HTAnchor_format(anchor);
    HTStream * pipe = NULL;

    /*
    **  The merge stream is a place holder for where we can put data when it
    **  arrives. We have two feeds: one from the cache and one from the net.
    **  We call the stream stack already now to get the right output stream.
    **  We can do this as we already know the content type from when we got the
    **  first part of the object.
    */
    HTStream * merge = HTMerge(HTStreamStack(format,
					     output_format, output_stream,
					     request, YES), 2);

    /*
    **  Now we create the MIME parser stream in partial data mode. We also
    **  set the target to our merge stream.
    */
    HTStream * me = HTMIMEConvert(request, param, input_format,
				  output_format, output_stream);
    me->mode |= HT_MIME_PARTIAL;
    me->target = merge;

#if 0
    /* JK: this doesn't work because this work is repeated before */
    /*
    **  Create the cache append stream, and a Tee stream
    */
    {
	HTStream * append = HTStreamStack(WWW_CACHE_APPEND, output_format,
					  output_stream, request, NO);
	if (append) me->target = HTTee(me->target, append, NULL);
    }
#endif

    /*
    **  Create the pipe buffer stream to buffer the data that we read
    **  from the network
    */
    if ((pipe = HTPipeBuffer(me->target, 0))) me->target = pipe;

    /*
    **  Now start the second load from the cache. First we read this data from
    **  the cache and then we flush the data that we have read from the net.
    */
    {
	HTRequest * cache_request = HTRequest_new();

	/*
	**  Set the output format to source and the output stream to the
	**  merge stream. As we have already set up the stream pipe, we just 
	**  load it as source.
	*/
	HTRequest_setOutputFormat(cache_request, WWW_SOURCE);
	HTRequest_setOutputStream(cache_request, merge);

	/*
	**  Bind the anchor to the new request and also register a local
	**  AFTER filter to flush the pipe buffer so that we can get
	**  rest of the data through. 
	*/
	HTRequest_setAnchor(cache_request, (HTAnchor *) anchor);
	HTRequest_addBefore(cache_request, HTCacheLoadFilter, NULL, NULL,
			    HT_FILTER_FIRST, YES);
	HTRequest_addAfter(cache_request, HTCacheFlushFilter, NULL, pipe,
			   HT_ALL, HT_FILTER_FIRST, YES);

	HTTRACE(STREAM_TRACE, "Partial..... Starting cache load\n");
	HTLoad(cache_request, NO);
    }
    return me;
#else
    return NULL;
#endif
}
Пример #19
0
PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
{
    if (me->state == MIME_TRANSPARENT) {
    	(*me->targetClass.put_character)(me->target, c);/* MUST BE FAST */
	return;
    }
    
    /* This slightly simple conversion just strips CR and turns LF to
    ** newline. On unix LF is \n but on Mac \n is CR for example.
    ** See NetToText for an implementation which preserves single CR or LF.
    */
    if (me->net_ascii) {
        c = FROMASCII(c);
	if (c == CR) return;
	else if (c == LF) c = '\n';
    }
    
    switch(me->state) {

    case MIME_IGNORE:
    	return;

    case MIME_TRANSPARENT:		/* Not reached see above */
    	(*me->targetClass.put_character)(me->target, c);
	return;
	
    case MIME_NET_ASCII:
    	(*me->targetClass.put_character)(me->target, c); /* MUST BE FAST */
	return;

    case NEWLINE:
	if (c != '\n' && WHITE(c)) {		/* Folded line */
	    me->state = me->fold_state;	/* pop state before newline */
	    break;
	}
	
	/*	else Falls through */
	
    case BEGINNING_OF_LINE:
        switch(c) {
	case 'c':
	case 'C':
	    me->check_pointer = "ontent-t";
	    me->if_ok = CONTENT_T;
	    me->state = CHECK;
	    break;
	case '\n':			/* Blank line: End of Header! */
	    {
	        if (TRACE) fprintf(stderr,
			"HTMIME: MIME content type is %s, converting to %s\n",
			HTAtom_name(me->format), HTAtom_name(me->targetRep));
		me->target = HTStreamStack(me->format, me->request, NO);
		if (!me->target) {
		    if (TRACE) fprintf(stderr, "MIME: Can't translate! ** \n");
		    me->target = me->sink;	/* Cheat */
		}
		if (me->target) {
		    me->targetClass = *me->target->isa;
		/* Check for encoding and select state from there @@ */
		
		    me->state = MIME_TRANSPARENT; /* From now push straigh through */
		} else {
		    me->state = MIME_IGNORE;		/* What else to do? */
		}
	    }
	    break;
	    
	default:
	   goto bad_field_name;
	   break;
	   
	} /* switch on character */
        break;
	
    case CHECK:				/* Check against string */
        if (TOLOWER(c) == *(me->check_pointer)++) {
	    if (!*me->check_pointer) me->state = me->if_ok;
	} else {		/* Error */
	    if (TRACE) fprintf(stderr,
	    	"HTMIME: Bad character `%c' found where `%s' expected\n",
		c, me->check_pointer - 1);
	    goto bad_field_name;
	}
	break;
	
    case CONTENT_T:
        switch(c) {
	case 'r':
	case 'R':
	    me->check_pointer = "ansfer-encoding:";
	    me->if_ok = CONTENT_TRANSFER_ENCODING;
	    me->state = CHECK;
	    break;
	    
	case 'y':
	case 'Y':
	    me->check_pointer = "pe:";
	    me->if_ok = CONTENT_TYPE;
	    me->state = CHECK;
	    break;
	    
	default:
	    goto bad_field_name;
	    
	} /* switch on character */
	break;
	
    case CONTENT_TYPE:
    case CONTENT_TRANSFER_ENCODING:
        me->field = me->state;		/* remember it */
	me->state = SKIP_GET_VALUE;
				/* Fall through! */
    case SKIP_GET_VALUE:
    	if (c == '\n') {
	   me->fold_state = me->state;
	   me->state = NEWLINE;
	   break;
	}
	if (WHITE(c)) break;	/* Skip white space */
	
	me->value_pointer = me->value;
	me->state = GET_VALUE;   
	/* Fall through to store first character */
	
    case GET_VALUE:
    	if (WHITE(c)) {			/* End of field */
	    *me->value_pointer = 0;
	    switch (me->field) {
	    case CONTENT_TYPE:
	        me->format = HTAtom_for(me->value);
		break;
	    case CONTENT_TRANSFER_ENCODING:
	        me->encoding = HTAtom_for(me->value);
		break;
	    default:		/* Should never get here */
	    	break;
	    }
	} else {
	    if (me->value_pointer < me->value + VALUE_SIZE - 1) {
	        *me->value_pointer++ = c;
		break;
	    } else {
	        goto value_too_long;
	    }
	}
	/* Fall through */
	
    case JUNK_LINE:
        if (c == '\n') {
	    me->state = NEWLINE;
	    me->fold_state = me->state;
	}
	break;
	
	
    } /* switch on state*/
    
    return;
    
value_too_long:
    if (TRACE) fprintf(stderr,
    	"HTMIME: *** Syntax error. (string too long)\n");
    
bad_field_name:				/* Ignore it */
    me->state = JUNK_LINE;
    return;
    
}