Пример #1
0
/*
**	Matches MIME constructions for content-types and others like
**	them, for example "text/html", "text/plain". It can also match
**	wild cards like "text/<star>" and "<star>/<star>. We use <star>
**	instead of * in order note to make C like comments :-)
*/
PUBLIC BOOL HTMIMEMatch (HTAtom * tmplate, HTAtom * actual)
{
    const char *t, *a;
    char *st, *sa;
    BOOL match = NO;

    if (tmplate && actual && (t = HTAtom_name(tmplate))) {
        if (!strcmp(t, "*"))
            return YES;

        if (strchr(t, '*') &&
                (a = HTAtom_name(actual)) &&
                (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {

            *sa = 0;
            *st = 0;

            if ((*(st-1)=='*' &&
                    (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
                    (*(st+1)=='*' && !strcasecomp(t,a)))
                match = YES;

            *sa = '/';
            *st = '/';
        }
    }
    return match;
}
Пример #2
0
/*
**	Returns the icon corresponding to content_type or content_encoding.
**	If no match is found then use "unknown icon"
*/
PUBLIC HTIconNode * HTIcon_find (HTFileMode	mode,
				 HTFormat	content_type,
				 HTEncoding	content_encoding)
{
    if (!icon_unknown) icon_unknown = icon_blank;
    if (mode == HT_IS_FILE) {
	const char * ct = content_type ? HTAtom_name(content_type) : NULL;
	const char * ce = content_encoding ? HTAtom_name(content_encoding) : NULL;
	HTList * cur = icons;
	HTIconNode * node;

	while ((node = (HTIconNode*)HTList_nextObject(cur))) {
	    char * slash = strchr(node->type_templ,'/');
	    if ((ct && slash && match(node->type_templ,ct)) ||
		(ce && !slash && HTStrMatch(node->type_templ,ce))) {
		return node;
	    }
	}
    } else if (mode == HT_IS_DIR) {
	return icon_dir ? icon_dir : icon_unknown;
    } else if (mode == HT_IS_BLANK) {
	return icon_blank ? icon_blank : icon_unknown;
    } else if (mode == HT_IS_PARENT) {
	return icon_parent ? icon_parent : icon_unknown;
    }
    return icon_unknown;
}
Пример #3
0
/*
 * Added by [email protected] (94/04/08)
 */
PRIVATE BOOL lang_match (HTAtom * tmplate, HTAtom * actual)
{
    const char *t, *a;
    char *st, *sa;
    BOOL match = NO;

    if (tmplate && actual &&
	(t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
	st = strchr(t, '_');
	sa = strchr(a, '_');
	if ((st != NULL) && (sa != NULL)) {
	    if (!strcasecomp(t, a))
	      match = YES;
	    else
	      match = NO;
	}
	else {
	    if (st != NULL) *st = 0;
	    if (sa != NULL) *sa = 0;
	    if (!strcasecomp(t, a))
	      match = YES;
	    else
	      match = NO;
	    if (st != NULL) *st = '_';
	    if (sa != NULL) *sa = '_';
	}
    }
    return match;
}
Пример #4
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;
}
Пример #5
0
/*		Find the cost of a filter stack
**		-------------------------------
**
**	Must return the cost of the same stack which StreamStack would set up.
**
** On entry,
**	length	The size of the data to be converted
*/
PUBLIC double HTStackValue (HTList *	theseConversions,
			    HTFormat	rep_in,
			    HTFormat	rep_out,
			    double	initial_value,
			    long int	length)
{
    int which_list;
    HTList* conversion[2];
    
    HTTRACE(CORE_TRACE, "StackValue.. Evaluating stream stack for %s worth %.3f to %s\n" _
	    HTAtom_name(rep_in) _ initial_value _ HTAtom_name(rep_out));

    if (rep_out == WWW_SOURCE || rep_out == rep_in) return 0.0;

    conversion[0] = theseConversions;
    conversion[1] = HTConversions;
    
    for(which_list = 0; which_list<2; which_list++)
     if (conversion[which_list]) {
        HTList * cur = conversion[which_list];
	HTPresentation * pres;
	while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
	    if (pres->rep == rep_in &&
		(pres->rep_out == rep_out || HTMIMEMatch(pres->rep_out, rep_out))) {
	        double value = initial_value * pres->quality;
		if (HTMaxSecs != 0.0)
		    value = value - (length*pres->secs_per_byte + pres->secs)
			                 /HTMaxSecs;
		return value;
	    }
	}
    }
    return NO_VALUE_FOUND;		/* Really bad */
}
Пример #6
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;
}
Пример #7
0
/*								 HTGetIcon()
** returns the icon corresponding to content_type or content_encoding.
*/
PUBLIC HTIconNode * HTGetIcon ARGS3(mode_t,	mode,
				    HTFormat,	content_type,
				    HTFormat,	content_encoding)
{
    if (!icon_unknown) icon_unknown = icon_blank;

    if ((mode & S_IFMT) == S_IFREG) {
	char * ct = content_type ? HTAtom_name(content_type) : NULL;
	char * ce = content_encoding ? HTAtom_name(content_encoding) : NULL;
	HTList * cur = icons;
	HTIconNode * node;

	while ((node = (HTIconNode*)HTList_nextObject(cur))) {
	    char * slash = strchr(node->type_templ,'/');
	    if ((ct && slash && match(node->type_templ,ct)) ||
		(ce && !slash && HTAA_templateMatch(node->type_templ,ce))) {
		return node;
	    }
	}
    } else if ((mode & S_IFMT) == S_IFDIR) {
	return icon_dir ? icon_dir : icon_unknown;
    } else if ((mode & S_IFMT) == S_IFLNK) {
	return icon_dir ? icon_dir : icon_unknown;	/* @@ */
    }

    return icon_unknown;
}
Пример #8
0
/*	Create a new coder and insert it into stream chain
**	--------------------------------------------------
**	Creating the content decoding stack is not based on quality factors as
**	we don't have the freedom as with content types. Specify whether you
**	you want encoding or decoding using the BOOL "encode" flag.
*/
PUBLIC HTStream * HTContentCodingStack (HTEncoding	encoding,
					HTStream *	target,
					HTRequest *	request,
					void *		param,
					BOOL		encode)
{
    HTList * coders[2];
    HTStream * top = target;
    HTCoding * pres = NULL;
    HTCoding * best_match = NULL;
    double best_quality = -1e30;		/* Pretty bad! */
    int cnt;
    if (!encoding || !request) {
	HTTRACE(CORE_TRACE, "Codings... Nothing applied...\n");
	return target ? target : HTErrorStream();
    }
    coders[0] = HTRequest_encoding(request);
    coders[1] = HTContentCoders;
    HTTRACE(CORE_TRACE, "C-E......... Looking for `%s\'\n" _ HTAtom_name(encoding));
    for (cnt=0; cnt < 2; cnt++) {
	HTList * cur = coders[cnt];
	while ((pres = (HTCoding *) HTList_nextObject(cur))) {
	    if ((pres->encoding == encoding || HTMIMEMatch(pres->encoding, encoding)) &&
		pres->quality > best_quality) {
		best_match = pres;
		best_quality = pres->quality;
	    }
	}
    }

    if (best_match) {
	HTTRACE(CORE_TRACE, "C-E......... Found `%s\'\n" _ HTAtom_name(best_match->encoding));
	if (encode) {
	    if (best_match->encoder)
		top = (*best_match->encoder)(request, param, encoding, top);
	} else {
	    if (best_match->decoder)
		top = (*best_match->decoder)(request, param, encoding, top);
	}
    } else if (!HTFormat_isUnityContent(encoding)) {

	/*
	**  If this is not a unity coding and we didn't find any coders
	**  that could handle it then put in a local file save stream
	**  instead of the stream that we got.
	*/
	if (encode) {
	    HTTRACE(CORE_TRACE, "C-E......... NOT FOUND - can't encode stream!\n");
	} else {
	    HTTRACE(CORE_TRACE, "C-E......... NOT FOUND - error!\n");
	    top = HTBlackHole();
	}
    }
    return top;
}
Пример #9
0
PRIVATE BOOL HTRank (HTRequest * request, HTArray * variants)
{
    HTContentDescription * cd;
    void ** data;
    if (!variants) {
	HTTRACE(PROT_TRACE, "Ranking..... No variants\n");
	return NO;
    }
    /* 
    **  Walk through the list of local and global preferences and find the
    **  overall q factor for each variant
    */
    cd = (HTContentDescription *) HTArray_firstObject(variants, data);
    while (cd) {
	double ctq_local  = type_value(cd->content_type, HTRequest_conversion(request));
	double ctq_global = type_value(cd->content_type, HTFormat_conversion());
	double clq_local  = lang_value(cd->content_language, HTRequest_language(request));
	double clq_global = lang_value(cd->content_language, HTFormat_language());
	double ceq_local  = encoding_value(cd->content_encoding, HTRequest_encoding(request));
	double ceq_global = encoding_value(cd->content_encoding, HTFormat_contentCoding());
	HTTRACE(PROT_TRACE, "Qualities... Content type: %.3f, Content language: %.3f, Content encoding: %.3f\n" _ 
		    HTMAX(ctq_local, ctq_global) _ 
		    HTMAX(clq_local, clq_global) _ 
		    HTMAX(ceq_local, ceq_global));
	cd->quality *= (HTMAX(ctq_local, ctq_global) *
			HTMAX(clq_local, clq_global) *
			HTMAX(ceq_local, ceq_global));
	cd = (HTContentDescription *) HTArray_nextObject(variants, data);
    }

    /* Sort the array of all our accepted preferences */
    HTArray_sort(variants, VariantSort);

    /* Write out the result */
#ifdef HTDEBUG 
    if (PROT_TRACE) {
	int cnt = 1;
	cd = (HTContentDescription *) HTArray_firstObject(variants, data);
	HTTRACE(PROT_TRACE, "Ranking.....\n");
	HTTRACE(PROT_TRACE, "RANK QUALITY CONTENT-TYPE         LANGUAGE ENCODING  FILE\n");
	while (cd) {
	    HTTRACE(PROT_TRACE, "%d.   %.4f  %-20.20s %-8.8s %-10.10s %s\n" _
		    cnt++ _
		    cd->quality _
		    cd->content_type ? HTAtom_name(cd->content_type) : "-" _
		    cd->content_language?HTAtom_name(cd->content_language):"-" _
		    cd->content_encoding?HTAtom_name(cd->content_encoding):"-" _
		    cd->filename ? cd->filename :"-");
	    cd = (HTContentDescription *) HTArray_nextObject(variants, data);
	}
    }
#endif /* HTDEBUG */
    return YES;
}
Пример #10
0
PRIVATE BOOL better_match (HTFormat f, HTFormat g)
{
    const char *p, *q;

    if (f && g  &&  (p = HTAtom_name(f))  &&  (q = HTAtom_name(g))) {
	int i,j;
	for(i=0 ; *p; p++) if (*p == '*') i++;
	for(j=0 ; *q; q++) if (*q == '*') j++;
	if (i < j) return YES;
    }
    return NO;
}
Пример #11
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;
}
Пример #12
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;
}
Пример #13
0
/*	Determine file format from file name -- string version
**	------------------------------------------------------
*/
PUBLIC char *HTFileMimeType ARGS2 (
			WWW_CONST char *,	filename,
                        WWW_CONST char *,   default_type)
{
  HTAtom *pencoding;
  HTFormat format;
  int compressed;

  format = HTFileFormat (filename, &pencoding, HTAtom_for (default_type),
                         &compressed);

  if (HTAtom_name (format))
    return HTAtom_name (format);
  else
    return default_type;
}
Пример #14
0
/*	Link me Anchor to another given one
**	-------------------------------------
*/
PUBLIC BOOL HTLink_add (HTAnchor *	source,
                        HTAnchor * 	destination,
                        HTLinkType	type,
                        HTMethod	method)
{
    if (source && destination) {
        HTTRACE(ANCH_TRACE, "Link create. from anchor %p to %p with type %s, method %s\n" _
                (void *) source _ (void *) destination _
                type ? HTAtom_name(type) : "NONE" _
                method != METHOD_INVALID ? HTMethod_name(method) : "NONE");
        if (!source->mainLink.dest) {
            source->mainLink.dest = destination;
            source->mainLink.type = type;
            source->mainLink.method = method;
        } else {
            HTLink * newLink = HTLink_new();
            newLink->dest = destination;
            newLink->type = type;
            newLink->method = method;
            if (!source->links) source->links = HTList_new();
            HTList_addObject (source->links, newLink);
        }
        if (!destination->parent->sources)
            destination->parent->sources = HTList_new();
        HTList_addObject (destination->parent->sources, source);
        return YES;
    } else
        HTTRACE(ANCH_TRACE, "Link........ Bad argument\n");
    return NO;
}
Пример #15
0
/*		Create a filter stack
**		---------------------
**
**	If a wildcard match is made, a temporary HTPresentation
**	structure is made to hold the destination format while the
**	new stack is generated. This is just to pass the out format to
**	MIME so far.  Storing the format of a stream in the stream might
**	be a lot neater.
**
*/
PUBLIC HTStream * HTStreamStack ARGS4(
	HTFormat,		rep_in,
	HTFormat,		rep_out,
	HTStream*,		sink,
	HTParentAnchor*,	anchor)
{
    HTPresentation temp;
    HTPresentation *match;
    HTStream *result;

    CTRACE((tfp, "HTFormat: Constructing stream stack for %s to %s\n",
		HTAtom_name(rep_in), HTAtom_name(rep_out)));

    /* don't return on WWW_SOURCE some people might like
     * to make use of the source!!!!  LJM
     */
#if 0
    if (rep_out == WWW_SOURCE || rep_out == rep_in)
	return sink;	/*  LJM */
#endif

    if (rep_out == rep_in) {
	result = sink;

    } else if ((match = HTFindPresentation(rep_in, rep_out, &temp))) {
	if (match == &temp) {
	    CTRACE((tfp, "StreamStack: Using %s\n", HTAtom_name(temp.rep_out)));
	} else {
	    CTRACE((tfp, "StreamStack: found exact match: %s\n",
			HTAtom_name(match->rep)));
	}
	result = (*match->converter)(match, anchor, sink);
    } else {
	result = NULL;
    }
    if (TRACE) {
	if (result && result->isa && result->isa->name) {
	    CTRACE((tfp, "StreamStack: Returning \"%s\"\n", result->isa->name));
	} else if (result) {
	    CTRACE((tfp, "StreamStack: Returning *unknown* stream!\n"));
	} else {
	    CTRACE((tfp, "StreamStack: Returning NULL!\n"));
	    CTRACE_FLUSH(tfp);	/* a crash may be imminent... - kw */
	}
    }
    return result;
}
Пример #16
0
/*	Create a new transfer coder and insert it into stream chain
**	-----------------------------------------------------------
**	Creating the content decoding stack is not based on quality factors as
**	we don't have the freedom as with content types. Specify whether you
**	you want encoding or decoding using the BOOL "encode" flag.
*/
PUBLIC HTStream * HTContentTransferCodingStack (HTEncoding	encoding,
						HTStream *	target,
						HTRequest *	request,
						void *		param,
						BOOL		encode)
{
    HTList * coders[2];
    HTStream * top = target;
    HTCoding * pres = NULL;
    int cnt;
    if (!encoding || !request) {
	HTTRACE(CORE_TRACE, "C-T-E..... Nothing applied...\n");
	return target ? target : HTErrorStream();
    }

    /*
    **  We use the same encoders/decoders as for Transfer-Encodings
    */
    coders[0] = HTRequest_transfer(request);
    coders[1] = HTTransferCoders;
    HTTRACE(CORE_TRACE, "C-T-E....... Looking for %s\n" _ HTAtom_name(encoding));
    for (cnt=0; cnt < 2; cnt++) {
	HTList * cur = coders[cnt];
	while ((pres = (HTCoding *) HTList_nextObject(cur))) {
	    if (pres->encoding == encoding) {
		HTTRACE(CORE_TRACE, "C-T-E....... Found...\n");
		if (encode) {
		    if (pres->encoder)
			top = (*pres->encoder)(request, param, encoding, top);
		    break;
		} else if (pres->decoder) {
		    top = (*pres->decoder)(request, param, encoding, top);
		    break;
		}
	    }
	}
    }

    /*
    **  If this is not a unity coding and we didn't find any coders
    **  that could handle it then put in a local file save stream
    **  instead of the stream that we got.
    */
    if (!HTFormat_isUnityTransfer(encoding) && target==top) {
	if (encode) {	    
	    HTTRACE(CORE_TRACE, "C-T-E....... NOT FOUND - removing encoding!\n");
	    HTAnchor_setContentTransferEncoding(HTRequest_anchor(request), NULL);
	} else {
	    HTTRACE(CORE_TRACE, "C-T-E....... NOT FOUND - error!\n");
	    top = HTBlackHole();
	}
    }
    return top;
}
Пример #17
0
/*		Find the cost of a filter stack
**		-------------------------------
**
**	Must return the cost of the same stack which StreamStack would set up.
**
** On entry,
**	length	The size of the data to be converted
*/
PUBLIC float HTStackValue ARGS4(
	HTFormat,		format_in,
	HTFormat,		rep_out,
	float,			initial_value,
	long int,		length)
{
    HTAtom * wildcard = HTAtom_for("*");

#ifndef DISABLE_TRACE
    if (www2Trace) fprintf(stderr,
    	"HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
	HTAtom_name(format_in),	initial_value,
	HTAtom_name(rep_out));
#endif
		
    if (rep_out == WWW_SOURCE ||
    	rep_out == format_in) return 0.0;

    if (!HTPresentations) HTFormatInit();	/* set up the list */
    
    {
	int n = HTList_count(HTPresentations);
	int i;
	HTPresentation * pres;
	for(i=0; i<n; i++) {
	    pres = HTList_objectAt(HTPresentations, i);
	    if (pres->rep == format_in && (
	    		pres->rep_out == rep_out ||
			pres->rep_out == wildcard)) {
	        float value = initial_value * pres->quality;
		if (HTMaxSecs != 0.0)
		value = value - (length*pres->secs_per_byte + pres->secs)
			                 /HTMaxSecs;
		return value;
	    }
	}
    }
    
    return -1e30;		/* Really bad */

}
Пример #18
0
/*		Find the cost of a filter stack
**		-------------------------------
**
**	Must return the cost of the same stack which StreamStack would set up.
**
** On entry,
**	length	The size of the data to be converted
*/
PUBLIC float HTStackValue ARGS4(
	HTFormat,		rep_in,
	HTFormat,		rep_out,
	float,			initial_value,
	long int,		length)
{
    HTAtom * wildcard = WWW_WILDCARD_REP_OUT;

    CTRACE((tfp, "HTFormat: Evaluating stream stack for %s worth %.3f to %s\n",
		HTAtom_name(rep_in), initial_value, HTAtom_name(rep_out)));

    if (rep_out == WWW_SOURCE || rep_out == rep_in)
	return 0.0;

    /* don't do anymore do it in the Lynx code at startup LJM */
    /* if (!HTPresentations) HTFormatInit(); */ /* set up the list */

    {
	int n = HTList_count(HTPresentations);
	int i;
	HTPresentation * pres;
	for (i = 0; i < n; i++) {
	    pres = (HTPresentation *)HTList_objectAt(HTPresentations, i);
	    if (pres->rep == rep_in &&
		(pres->rep_out == rep_out || pres->rep_out == wildcard)) {
		float value = initial_value * pres->quality;
		if (HTMaxSecs != 0.0)
		    value = value - (length*pres->secs_per_byte + pres->secs)
					 /HTMaxSecs;
		return value;
	    }
	}
    }

    return (float) -1e30;	/* Really bad */

}
Пример #19
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 */
}
Пример #20
0
PRIVATE double encoding_value (HTAtom * encoding, HTList * accepted)
{
    if (!encoding) return (1.0);
    if (accepted) {
	HTList * cur = accepted;
	HTAcceptNode * node;
	HTAcceptNode * wild = NULL;
	const char * e = HTAtom_name(encoding);
	if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
	    return (1.0);
	while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
	    if (node->atom == encoding)
		return node->quality;
	    else if (HTMIMEMatch(node->atom, encoding))
		wild = node;
	}
	if (wild) return wild->quality;
	else return (0.0);				  /* Nothing matched */
    }
    return (1.0);				  /* We accept all encodings */
}
Пример #21
0
/*
** request_terminater : global filter to delete the requests
** Funtion's type : HTNetAfter
*/ 
PRIVATE int terminate_handler (HTRequest * request, HTResponse * response,
                               void * param, int status) 
{
    my_headers(request);

     if (response) {
        HTPrint ("\tStatus:%d\n\tContent-length:%d\n\tIs Cachable:%c\n\tis Cached:%c\n\tReason: %s\n",\
                  status, HTResponse_length(response),\
                  (HTResponse_isCachable(response))?'Y':'N',\
                  (HTResponse_isCached(response,YES))?'Y':'N', \
                  (HTResponse_reason(response))?HTResponse_reason(response):"NULL");
            HTPrint ("\tFormat : %s \n",(char *)HTAtom_name(HTResponse_format(response))); 
    }
    else 
        HTPrint ("\tResponse NULL\n");
    

    /* Terminate libwww */
    HTProfile_delete();

    exit(0);
}
Пример #22
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;
}
Пример #23
0
/*		Create a filter stack
**		---------------------
**
**	If a wildcard match is made, a temporary HTPresentation
**	structure is made to hold the destination format while the
**	new stack is generated. This is just to pass the out format to
**	MIME so far.  Storing the format of a stream in the stream might
**	be a lot neater.
*/
PUBLIC HTStream * HTStreamStack ARGS5(
	HTFormat,		format_in,
	HTFormat,		rep_out,
        int,                    compressed,
	HTStream*,		sink,
	HTParentAnchor*,	anchor)
{
  HTAtom * wildcard = HTAtom_for("*");
  HTPresentation temp;

  /* Inherit force_dump_to_file from mo-www.c. */
  extern int force_dump_to_file;

#ifndef DISABLE_TRACE
  if (www2Trace) 
    fprintf(stderr,
            "[HTStreamStack] Constructing stream stack for %s to %s\n",
            HTAtom_name(format_in),	
            HTAtom_name(rep_out));
#endif
#ifndef DISABLE_TRACE
  if (www2Trace)
    fprintf (stderr,
             "               Compressed is %d\n", compressed);
#endif
    
  if (rep_out == WWW_SOURCE ||
      rep_out == format_in) 
    {
#ifndef DISABLE_TRACE
      if (www2Trace)
        fprintf (stderr,
                 "[HTStreamStack] rep_out == WWW_SOURCE | rep_out == format_in; returning sink\n");
#endif
      return sink;
    }
  
  if (!HTPresentations) 
    HTFormatInit();	/* set up the list */
  
  if (force_dump_to_file && format_in != WWW_MIME)
    {
      return HTSaveAndExecute (NULL, anchor, sink, format_in, compressed);
    }
  
  {
    int n = HTList_count(HTPresentations);
    int i;
    HTPresentation * pres;
    for(i=0; i<n; i++) 
      {
        pres = HTList_objectAt(HTPresentations, i);
#ifndef DISABLE_TRACE
        if (www2Trace)
          {
            fprintf (stderr, "HTFormat: looking at pres '%s'\n",
                     HTAtom_name (pres->rep));
            if (pres->command)
              fprintf (stderr, "HTFormat: pres->command is '%s'\n",
                       pres->command);
            else
              fprintf (stderr, "HTFormat: pres->command doesn't exist\n");
          }
#endif
        if (pres->rep == format_in ||
            partial_wildcard_matches (pres->rep, format_in))
          {
            if (pres->command && strstr (pres->command, "mosaic-internal-present"))
              {
#ifndef DISABLE_TRACE
                if (www2Trace)
                  fprintf (stderr, "[HTStreamStack] HEY HEY HEY caught internal-present\n");
#endif
                return HTPlainPresent (pres, anchor, sink, format_in, compressed);
              }
            if (pres->rep_out == rep_out)
              {
#ifndef DISABLE_TRACE
                if (www2Trace)
                  fprintf (stderr,
                           "[HTStreamStack] pres->rep_out == rep_out\n");
#endif
                return (*pres->converter)(pres, anchor, sink, format_in, compressed);
              }
            if (pres->rep_out == wildcard) 
              {
#ifndef DISABLE_TRACE
                if (www2Trace)
                  fprintf (stderr,
                           "[HTStreamStack] pres->rep_out == wildcard\n");
#endif
                temp = *pres;/* make temp conversion to needed fmt */
                temp.rep_out = rep_out;		/* yuk */
                return (*pres->converter)(&temp, anchor, sink, format_in, compressed);
              }
          }
      }
  }

#ifndef DISABLE_TRACE
  if (www2Trace)
    {
      fprintf (stderr, "[HTStreamStack] Returning NULL at bottom.\n");
    }
#endif
  
  return NULL;
}
Пример #24
0
static int partial_wildcard_matches (HTFormat r1, HTFormat r2)
{
  /* r1 is the presentation format we're currently looking at out
     of the list we understand.  r2 is the one we need to get to. */
  char *s1, *s2, *subtype1 = NULL, *subtype2 = NULL;
  int i;

  s1 = HTAtom_name (r1);
  s2 = HTAtom_name (r2);

  if (!s1 || !s2)
    return 0;
  
  s1 = strdup (s1);
  s2 = strdup (s2);

  for (i = 0; i < strlen (s1); i++)
    if (s1[i] == '/')
      {
        s1[i] = '\0';
        subtype1 = &(s1[i+1]);
        /* Now s1 contains the main type and subtype1 contains
           the subtype. */
        goto done1;
      }

 done1:
  if (!subtype1)
    goto nope;
  
  /* Bail if we don't have a wildcard possibility. */
  if (subtype1[0] != '*')
    goto nope;

  for (i = 0; i < strlen (s2); i++)
    if (s2[i] == '/')
      {
        s2[i] = '\0';
        subtype2 = &(s2[i+1]);
        /* Now s2 contains the main type and subtype2 contains
           the subtype. */
        goto done2;
      }

 done2:
  if (!subtype2)
    goto nope;

  /* Bail if s1 and s2 aren't the same and s1[0] isn't '*'. */
  if (strcmp (s1, s2) && s1[0] != '*')
    goto nope;

  /* OK, so now either we have the same main types or we have a wildcard
     type for s1.  We also know that we have a wildcard possibility in
     s1.  Therefore, at this point, we have a match. */
  free (s1);
  free (s2);
  return 1;

 nope:
  free (s1);
  free (s2);
  return 0;
}
Пример #25
0
/*	Determine the content of an file name
**	-------------------------------------
**  Use the set of bindings to find the combination of language,
**  media type, encoding, and transfer encoding  of a given anchor.
**  If more than one suffix is found they are all searched. The last suffix
**  has highest priority, the first one lowest. See also HTBind_getBindings()
**  Either of format, encoding, or language can be NULL
**  Returns the format, encoding, and language found
*/
PUBLIC BOOL HTBind_getFormat (const char *	filename,
			      HTFormat *	format,
			      HTEncoding *	enc,
			      HTEncoding *	cte,
			      HTLanguage *	lang,
			      double *		quality)
{
    int sufcnt=0;
    char *file=NULL;
#ifdef HT_REENTRANT
    char *lasts;					     /* For strtok_r */
#endif
    if (!HTBindings) HTBind_init();
    if (*quality < HT_EPSILON)
	*quality = 1.0;			           /* Set to a neutral value */
    StrAllocCopy(file, filename);
    HTUnEscape(file);				   /* Unescape the file name */
#ifdef HT_REENTRANT
    if (strtok_r(file, HTDelimiters, &lasts)) {	 /* Do we have any suffixes? */
#else
    if (strtok(file, HTDelimiters)) { 		 /* Do we have any suffixes? */
#endif /* HT_REENTRANT */
	char *suffix;
#ifdef HT_REENTRANT
	while ((suffix=(char*)strtok_r(NULL, HTDelimiters, &lasts)) != NULL) {
#else
	while ((suffix=strtok(NULL, HTDelimiters)) != NULL) {
#endif /* HT_REENTRANT */
	    HTBind *suff=NULL;
	    int hash;
	    unsigned char * p;
	    HTTRACE(BIND_TRACE, "Get Binding. Look for '%s\' " _ suffix);
	    sufcnt++;

	    /* Select list from hash table */
	    for (p=suffix, hash=0; *p; p++) {
		hash = (hash * 3 + TOLOWER(*p)) % HT_L_HASH_SIZE;
	    }

	    /* Now search list for entries (case or non case sensitive) */
	    if (HTBindings[hash]) {
		HTList *cur = HTBindings[hash];
		while ((suff = (HTBind *) HTList_nextObject(cur))) {
		    if ((HTCaseSen && !strcmp(suff->suffix, suffix)) ||
			!strcasecomp(suff->suffix, suffix)) {
			HTTRACE(BIND_TRACE, "Found!\n");
			if (suff->type && format) *format = suff->type;
			if (suff->encoding && enc) *enc = suff->encoding;
			if (suff->transfer && cte) *cte = suff->transfer;
			if (suff->language && lang) *lang = suff->language;
			if (suff->quality > HT_EPSILON)
			    *quality *= suff->quality;
			break;
		    }
		}
	    }
	    if (!suff) {	/* We don't have this suffix - use default */
		HTTRACE(BIND_TRACE, "Not found - use default for \'*.*\'\n");
		if (format) *format = unknown_suffix.type;
		if (enc) *enc = unknown_suffix.encoding;
		if (cte) *cte = unknown_suffix.transfer;
		if (lang) *lang = unknown_suffix.language;
		*quality = unknown_suffix.quality;
	    }
	} /* while we still have suffixes */
    }
    if (!sufcnt) {		/* No suffix so use default value */
	HTTRACE(BIND_TRACE, "Get Binding. No suffix found - using default '%s\'\n" _ filename);
	if (format) *format = no_suffix.type;
	if (enc) *enc = no_suffix.encoding;
	if (cte) *cte = no_suffix.transfer;
	if (lang) *lang = no_suffix.language;
	*quality = no_suffix.quality;
    }
    HTTRACE(BIND_TRACE, "Get Binding. Result for '%s\' is: type='%s\', encoding='%s\', cte='%s\', language='%s\' with quality %.2f\n" _ 
		filename _ 
		(format && *format) ? HTAtom_name(*format) : "unknown" _ 
		(enc && *enc) ? HTAtom_name(*enc) : "unknown" _ 
		(cte && *cte) ? HTAtom_name(*cte) : "unknown" _ 
		(lang && *lang) ? HTAtom_name(*lang) : "unknown" _ 
		*quality);
    HT_FREE(file);
    return YES;
}
Пример #26
0
PUBLIC BOOL HTAnchor_setLevel (HTParentAnchor * me, HTLevel level)
{
    return HTAnchor_addFormatParam(me, "level", HTAtom_name(level));
}
Пример #27
0
PUBLIC BOOL HTAnchor_setCharset (HTParentAnchor * me, HTCharset charset)
{
    return HTAnchor_addFormatParam(me, "charset", HTAtom_name(charset));
}
Пример #28
0
PUBLIC BOOL HTResponse_setCharset (HTResponse * me, HTCharset charset)
{
    return HTResponse_addFormatParam(me, "charset", HTAtom_name(charset));
}
Пример #29
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;
}
Пример #30
0
/* PRIVATE						multi_match()
**
**	Check if actual filename (split in parts) fulfills
**	the requirements.
*/
PRIVATE BOOL multi_match (char ** required, int m, char ** actual, int n)
{
    int c;
    int i,j;

#ifdef VMS
    for(c=0;  c<m && c<n && !strcasecomp(required[c], actual[c]);  c++);
#else /* not VMS */
    for(c=0;  c<m && c<n && !strcmp(required[c], actual[c]);  c++);
#endif /* not VMS */

    if (!c) return NO;		/* Names differ rigth from start */

    for(i=c; i<m; i++) {
	BOOL found = NO;
	for(j=c; j<n; j++) {
#ifdef VMS
	    if (!strcasecomp(required[i], actual[j])) {
#else /* not VMS */
	    if (!strcmp(required[i], actual[j])) {
#endif /* not VMS */
		found = YES;
		break;
	    }
	}
	if (!found) return NO;
    }
    return YES;
}


/*
**	Get multi-match possibilities for a given file
**	----------------------------------------------
** On entry:
**	path	absolute path to one file in a directory,
**		may end in .multi.
** On exit:
**	returns	a list of ContentDesription structures
**		describing the mathing files.
**
*/
PRIVATE HTArray * dir_matches (char * path)
{
    static char * required[MAX_SUFF+1];
    static char * actual[MAX_SUFF+1];
    int m,n;
    char * dirname = NULL;
    char * basename = NULL;
    int baselen;
    char * multi = NULL;
    DIR * dp;
    struct dirent * dirbuf;
    HTArray * matches = NULL;
#ifdef HT_REENTRANT
    struct dirent result;				         /* For readdir_r */
#endif

    if (!path) return NULL;

    StrAllocCopy(dirname, path);
    basename = (strrchr(dirname, '/'));
    if (!basename)
	goto dir_match_failed;
    *basename++ = 0;

    multi = strrchr(basename, MULTI_SUFFIX[0]);
    if (multi && !strcasecomp(multi, MULTI_SUFFIX))
	*multi = 0;
    baselen = strlen(basename);

    m = HTSplitFilename(basename, required);

    dp = opendir(dirname);
    if (!dp) {
	HTTRACE(PROT_TRACE, "Warning..... Can't open directory %s\n" _ dirname);
	goto dir_match_failed;
    }

    matches = HTArray_new(VARIANTS);
#ifdef HAVE_READDIR_R_2
	while ((dirbuf = (struct dirent *) readdir_r(dp, &result))) {
#elif defined(HAVE_READDIR_R_3)
        while (readdir_r(dp, &result, &dirbuf) == 0) {
#else
	while ((dirbuf = readdir(dp))) {
#endif /* HAVE_READDIR_R_2 */
	if (!dirbuf->d_ino) continue;	/* Not in use */
	if (!strcmp(dirbuf->d_name,".") ||
	    !strcmp(dirbuf->d_name,"..") ||
	    !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
	    continue;

	/* Use of direct->namlen is only valid in BSD'ish system */
	/* Thanks to [email protected] (Chip Rosenthal) */
	/* if ((int)(dirbuf->d_namlen) >= baselen) { */
	if ((int) strlen(dirbuf->d_name) >= baselen) {
	    n = HTSplitFilename(dirbuf->d_name, actual);
	    if (multi_match(required, m, actual, n)) {
		HTContentDescription * cd;
		if ((cd = (HTContentDescription  *)
		     HT_CALLOC(1, sizeof(HTContentDescription))) == NULL)
		    HT_OUTOFMEM("dir_matches");
		if (HTBind_getFormat(dirbuf->d_name,
				     &cd->content_type,
				     &cd->content_encoding,
				     &cd->content_transfer,
				     &cd->content_language,
				     &cd->quality)) {
		    if (cd->content_type) {
			if ((cd->filename = (char *) HT_MALLOC(strlen(dirname) + 2 + strlen(dirbuf->d_name))) == NULL)
			    HT_OUTOFMEM("dir_matches");
			sprintf(cd->filename, "%s/%s", dirname, dirbuf->d_name);
			HTArray_addObject(matches, (void *) cd);
		    } else {
			HT_FREE(cd);
		    }
		} else {
		    HT_FREE(cd);
		}
	    }
	}
    }
    closedir(dp);

  dir_match_failed:
    HT_FREE(dirname);
    return matches;
}


/*
**	Get the best match for a given file
**	-----------------------------------
** On entry:
**	req->conversions  accepted content-types
**	req->encodings	  accepted content-transfer-encodings
**	req->languages	  accepted content-languages
**	path		  absolute pathname of the filename for
**			  which the match is desired.
** On exit:
**	returns	a newly allocated absolute filepath.
*/
PRIVATE char * HTGetBest (HTRequest * req, char * path)
{
    HTArray * variants = NULL;
    char * representation = NULL;

    if (!path || !*path) return NULL;

    if ((variants = dir_matches(path)) == NULL) {
	HTTRACE(PROT_TRACE, "No matches.. for \"%s\"\n" _ path);
	return NULL;
    }

#ifdef HTDEBUG
    if (PROT_TRACE) {
	void ** data;
	HTContentDescription * cd = HTArray_firstObject(variants, data);
	HTTRACE(PROT_TRACE, "Multi....... Possibilities for \"%s\"\n" _ path);
	HTTRACE(PROT_TRACE, "     QUALITY CONTENT-TYPE         LANGUAGE ENCODING  FILE\n");
	while (cd) {
	    HTTRACE(PROT_TRACE, "     %.4f  %-20.20s %-8.8s %-10.10s %s\n" _
		    cd->quality _
		    cd->content_type    ?HTAtom_name(cd->content_type)  :"-\t" _
		    cd->content_language?HTAtom_name(cd->content_language):"-" _
		    cd->content_encoding?HTAtom_name(cd->content_encoding):"-" _
		    cd->filename        ?cd->filename                    :"-");
	    cd = (HTContentDescription *) HTArray_nextObject(variants, data);
	}
    }
#endif /* HTDEBUG */

    /*
    ** Finally get the best variant which is readable
    */
    if (HTRank(req, variants)) {
	void ** data;
	HTContentDescription * cd = HTArray_firstObject(variants, data);
	while (cd) {
	    if (cd->filename) {
		if (access(cd->filename, R_OK) != -1)
		    StrAllocCopy(representation, cd->filename);
		else HTTRACE(PROT_TRACE, "Multi....... `%s\' is not readable\n" _ 
			    cd->filename);
	    }
	    HT_FREE(cd->filename);
	    HT_FREE(cd);
	    cd = (HTContentDescription *) HTArray_nextObject(variants, data);
	}
    }
    HTArray_delete(variants);
    return representation;
}



PRIVATE int welcome_value (char * name)
{
    HTList * cur = welcome_names;
    char * welcome;
    int v = 0;

    while ((welcome = (char*)HTList_nextObject(cur))) {
	v++;
	if (!strcmp(welcome,name)) return v;
    }
    return 0;
}



PRIVATE char * get_best_welcome (char * path)
{
    char * best_welcome = NULL;
    int best_value = 0;
    DIR * dp;
    struct dirent * dirbuf;
    char * last = strrchr(path, '/');

    if (!welcome_names) {
	HTAddWelcome("Welcome.html");
	HTAddWelcome("welcome.html");
#if 0
	HTAddWelcome("Index.html");
#endif
	HTAddWelcome("index.html");
    }

    if (last && last!=path) *last = 0;
    dp = opendir(path);
    if (last && last!=path) *last='/';
    if (!dp) {
	HTTRACE(PROT_TRACE, "Warning..... Can't open directory %s\n" _ path);
	return NULL;
    }
    while ((dirbuf = readdir(dp))) {
	if (!dirbuf->d_ino ||
	    !strcmp(dirbuf->d_name,".") ||
	    !strcmp(dirbuf->d_name,"..") ||
	    !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
	    continue;
	else {
	    int v = welcome_value(dirbuf->d_name);
	    if (v > best_value) {
		best_value = v;
		StrAllocCopy(best_welcome, dirbuf->d_name);
	    }
	}
    }
    closedir(dp);

    if (best_welcome) {
	char * welcome;
	if ((welcome = (char *) HT_MALLOC(strlen(path) + strlen(best_welcome)+2)) == NULL)
	    HT_OUTOFMEM("get_best_welcome");
	sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
	HT_FREE(best_welcome);
	HTTRACE(PROT_TRACE, "Welcome..... \"%s\"\n" _ welcome);
	return welcome;
    }
    return NULL;
}