diff options
Diffstat (limited to 'WWW')
-rw-r--r-- | WWW/Library/Implementation/HTAccess.c | 7 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTAnchor.c | 37 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTAnchor.h | 5 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTChunk.c | 75 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTChunk.h | 10 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTFile.c | 9 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTFormat.c | 82 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTFormat.h | 13 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTMIME.c | 1506 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTMIME.h | 8 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTParse.c | 26 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTStream.h | 11 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTTP.c | 547 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTUtils.h | 1 | ||||
-rw-r--r-- | WWW/Library/djgpp/makefile | 8 |
15 files changed, 1193 insertions, 1152 deletions
diff --git a/WWW/Library/Implementation/HTAccess.c b/WWW/Library/Implementation/HTAccess.c index 6391cceb..9010cf26 100644 --- a/WWW/Library/Implementation/HTAccess.c +++ b/WWW/Library/Implementation/HTAccess.c @@ -971,6 +971,13 @@ PRIVATE BOOL HTLoadDocument ARGS4( ** So, instead, we'll go all the way back to the top of getfile ** in LYGetFile.c when the status is HT_REDIRECTING. This may ** seem bizarre, but it works like a charm! - FM + ** + ** Actually, the location header for redirections is now again + ** picked up in HTMIME.c. But that's an internal matter between + ** HTTP.c and HTMIME.c, is still under control of HTLoadHTTP for + ** http URLs, is done in a way that doesn't load the redirection + ** response's body (except when wanted as an error fallback), and + ** thus need not concern us here. - kw 1999-12-02 */ CTRACE((tfp, "HTAccess: '%s' is a redirection URL.\n", address_to_load)); diff --git a/WWW/Library/Implementation/HTAnchor.c b/WWW/Library/Implementation/HTAnchor.c index 346f595c..e9ebe1f3 100644 --- a/WWW/Library/Implementation/HTAnchor.c +++ b/WWW/Library/Implementation/HTAnchor.c @@ -598,6 +598,28 @@ PRIVATE void deleteLinks ARGS1( } } +#ifdef SOURCE_CACHE +PUBLIC void HTAnchor_clearSourceCache ARGS1( + HTParentAnchor *, me) +{ + /* + * Clean up the source cache, if any. + */ + if (me->source_cache_file) { + CTRACE((tfp, "SourceCache: Removing file %s\n", + me->source_cache_file)); + LYRemoveTemp(me->source_cache_file); + FREE(me->source_cache_file); + } + if (me->source_cache_chunk) { + CTRACE((tfp, "SourceCache: Removing memory chunk %p\n", + (void *)me->source_cache_chunk)); + HTChunkFree(me->source_cache_chunk); + me->source_cache_chunk = NULL; + } +} +#endif /* SOURCE_CACHE */ + PUBLIC BOOL HTAnchor_delete ARGS1( HTParentAnchor *, me) { @@ -722,20 +744,7 @@ PUBLIC BOOL HTAnchor_delete ARGS1( FREE(me->owner); FREE(me->RevTitle); #ifdef SOURCE_CACHE - /* - * Clean up the source cache, if any. - */ - if (me->source_cache_file) { - CTRACE((tfp, "Removing source cache file %s\n", - me->source_cache_file)); - LYRemoveTemp(me->source_cache_file); - FREE(me->source_cache_file); - } - if (me->source_cache_chunk) { - CTRACE((tfp, "Removing memory source cache %p\n", - (void *)me->source_cache_chunk)); - HTChunkFree(me->source_cache_chunk); - } + HTAnchor_clearSourceCache(me); #endif if (me->FileCache) { FILE *fd; diff --git a/WWW/Library/Implementation/HTAnchor.h b/WWW/Library/Implementation/HTAnchor.h index de49d162..119f712b 100644 --- a/WWW/Library/Implementation/HTAnchor.h +++ b/WWW/Library/Implementation/HTAnchor.h @@ -189,6 +189,11 @@ extern HTAnchor * HTAnchor_findSimpleAddress PARAMS(( extern BOOL HTAnchor_delete PARAMS(( HTParentAnchor * me)); +#ifdef SOURCE_CACHE +extern void HTAnchor_clearSourceCache PARAMS(( + HTParentAnchor * me)); +#endif + /* Move an anchor to the head of the list of its siblings ** ------------------------------------------------------ ** diff --git a/WWW/Library/Implementation/HTChunk.c b/WWW/Library/Implementation/HTChunk.c index 6b8c73f1..d38c5808 100644 --- a/WWW/Library/Implementation/HTChunk.c +++ b/WWW/Library/Implementation/HTChunk.c @@ -15,7 +15,7 @@ PUBLIC HTChunk * HTChunkCreate ARGS1 (int,grow) { HTChunk * ch = (HTChunk *) calloc(1, sizeof(HTChunk)); if (ch == NULL) - outofmem(__FILE__, "creation of chunk"); + outofmem(__FILE__, "creation of chunk"); ch->data = 0; ch->growby = grow; @@ -23,6 +23,23 @@ PUBLIC HTChunk * HTChunkCreate ARGS1 (int,grow) ch->allocated = 0; return ch; } +PUBLIC HTChunk * HTChunkCreateMayFail ARGS2 (int,grow, int,failok) +{ + HTChunk * ch = (HTChunk *) calloc(1, sizeof(HTChunk)); + if (ch == NULL) { + if (!failok) { + outofmem(__FILE__, "creation of chunk"); + } else { + return ch; + } + } + ch->data = 0; + ch->growby = grow; + ch->size = 0; + ch->allocated = 0; + ch->failok = failok; + return ch; +} /* Create a chunk with a certain allocation unit and ensured size ** -------------- @@ -31,7 +48,7 @@ PUBLIC HTChunk * HTChunkCreate2 ARGS2 (int,grow, size_t, needed) { HTChunk * ch = (HTChunk *) calloc(1, sizeof(HTChunk)); if (ch == NULL) - outofmem(__FILE__, "HTChunkCreate2"); + outofmem(__FILE__, "HTChunkCreate2"); ch->growby = grow; if (needed > 0) { @@ -77,11 +94,18 @@ PUBLIC void HTChunkFree ARGS1 (HTChunk *,ch) PUBLIC void HTChunkPutc ARGS2 (HTChunk *,ch, char,c) { if (ch->size >= ch->allocated) { + char *data; ch->allocated = ch->allocated + ch->growby; - ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated) - : (char *)calloc(1, ch->allocated); - if (!ch->data) - outofmem(__FILE__, "HTChunkPutc"); + data = ch->data ? (char *)realloc(ch->data, ch->allocated) + : (char *)calloc(1, ch->allocated); + if (data) { + ch->data = data; + } else if (ch->failok) { + HTChunkClear(ch); /* allocation failed, clear all data - kw */ + return; /* caller should check ch->allocated - kw */ + } else { + outofmem(__FILE__, "HTChunkPutc"); + } } ch->data[ch->size++] = c; } @@ -94,11 +118,11 @@ PUBLIC void HTChunkEnsure ARGS2 (HTChunk *,ch, int,needed) { if (needed <= ch->allocated) return; ch->allocated = needed-1 - ((needed-1) % ch->growby) - + ch->growby; /* Round up */ + + ch->growby; /* Round up */ ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated) : (char *)calloc(1, ch->allocated); if (ch->data == NULL) - outofmem(__FILE__, "HTChunkEnsure"); + outofmem(__FILE__, "HTChunkEnsure"); } PUBLIC void HTChunkPutb ARGS3 (HTChunk *,ch, CONST char *,b, int,l) @@ -106,12 +130,19 @@ PUBLIC void HTChunkPutb ARGS3 (HTChunk *,ch, CONST char *,b, int,l) int needed = ch->size + l; if (l <= 0) return; if (needed > ch->allocated) { + char *data; ch->allocated = needed-1 - ((needed-1) % ch->growby) + ch->growby; /* Round up */ - ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated) - : (char *)calloc(1, ch->allocated); - if (ch->data == NULL) + data = ch->data ? (char *)realloc(ch->data, ch->allocated) + : (char *)calloc(1, ch->allocated); + if (data) { + ch->data = data; + } else if (ch->failok) { + HTChunkClear(ch); /* allocation failed, clear all data - kw */ + return; /* caller should check ch->allocated - kw */ + } else { outofmem(__FILE__, "HTChunkPutb"); + } } memcpy(ch->data + ch->size, b, l); ch->size += l; @@ -142,12 +173,19 @@ PUBLIC void HTChunkPutUtf8Char ARGS2( utflen = 0; if (ch->size + utflen > ch->allocated) { + char *data; int growby = (ch->growby >= utflen) ? ch->growby : utflen; ch->allocated = ch->allocated + growby; - ch->data = ch->data ? (char *)realloc(ch->data, ch->allocated) - : (char *)calloc(1, ch->allocated); - if (!ch->data) - outofmem(__FILE__, "HTChunkPutUtf8Char"); + data = ch->data ? (char *)realloc(ch->data, ch->allocated) + : (char *)calloc(1, ch->allocated); + if (data) { + ch->data = data; + } else if (ch->failok) { + HTChunkClear(ch); /* allocation failed, clear all data - kw */ + return; /* caller should check ch->allocated - kw */ + } else { + outofmem(__FILE__, "HTChunkPutUtf8Char"); + } } switch (utflen) { @@ -200,6 +238,9 @@ PUBLIC void HTChunkTerminate ARGS1 (HTChunk *,ch) PUBLIC void HTChunkPuts ARGS2 (HTChunk *,ch, CONST char *,s) { CONST char * p; - for (p=s; *p; p++) - HTChunkPutc(ch, *p); + for (p=s; *p; p++) { + HTChunkPutc(ch, *p); + if (ch->allocated == 0) + return; /* must have been allocation failure - kw */ + } } diff --git a/WWW/Library/Implementation/HTChunk.h b/WWW/Library/Implementation/HTChunk.h index e6cf19c8..2145f362 100644 --- a/WWW/Library/Implementation/HTChunk.h +++ b/WWW/Library/Implementation/HTChunk.h @@ -21,6 +21,7 @@ typedef struct { int growby; /* Allocation unit in bytes */ int allocated; /* Current size of *data */ char * data; /* Pointer to malloced area or 0 */ + int failok; /* allowed to fail without exiting program? */ } HTChunk; @@ -43,6 +44,15 @@ typedef struct { extern HTChunk * HTChunkCreate PARAMS((int growby)); /* + * Create a chunk for which an allocation error is not a fatal application + * error if failok != 0, but merely resets the chunk. When using a chunk + * created this way, the caller should always check whether the contents + * are ok each time after data have been appended. + * The create call may also fail and will reurn NULL in that case. - kw + */ +extern HTChunk * HTChunkCreateMayFail PARAMS((int growby, int failok)); + +/* * Like HTChunkCreate but with initial allocation - kw * */ diff --git a/WWW/Library/Implementation/HTFile.c b/WWW/Library/Implementation/HTFile.c index b5ad32af..4ecf8820 100644 --- a/WWW/Library/Implementation/HTFile.c +++ b/WWW/Library/Implementation/HTFile.c @@ -2510,7 +2510,14 @@ PUBLIC int HTLoadFile ARGS4( FREE(nodename); return status; /* document loaded, maybe partial */ - } /* end if localname is a directory */ + } /* end if localname is a directory */ + + if (S_ISREG(dir_info.st_mode)) { +#ifdef INT_MAX + if (dir_info.st_size <= INT_MAX) +#endif + anchor->content_length = dir_info.st_size; + } } /* end if file stat worked */ diff --git a/WWW/Library/Implementation/HTFormat.c b/WWW/Library/Implementation/HTFormat.c index 1e86af35..901452b3 100644 --- a/WWW/Library/Implementation/HTFormat.c +++ b/WWW/Library/Implementation/HTFormat.c @@ -516,6 +516,7 @@ PUBLIC void HTDisplayPartial NOARGS /* ** HText_getNumOfLines() = "current" number of complete lines received ** NumOfLines_partial = number of lines at the moment of last repaint. + ** (we update NumOfLines_partial only when we repaint the display.) ** ** display_partial could only be enabled in HText_new() ** so a new HTMainText object available - all HText_ functions use it, @@ -528,11 +529,13 @@ PUBLIC void HTDisplayPartial NOARGS ** ** So repaint the page only when necessary: */ - if (((Newline_partial + display_lines) > NumOfLines_partial) + int Newline_partial = LYGetNewline(); + + if (((Newline_partial + display_lines) - 1 >= NumOfLines_partial) /* current page not complete... */ && (partial_threshold > 0 ? - ((Newline_partial + partial_threshold) < HText_getNumOfLines()) : - ((Newline_partial + display_lines) < HText_getNumOfLines())) + ((Newline_partial + partial_threshold) -1 <= HText_getNumOfLines()) : + ((Newline_partial + display_lines) - 1 <= HText_getNumOfLines())) /* * Originally we rendered by increments of 2 lines, * but that got annoying on slow network connections. @@ -598,6 +601,7 @@ PUBLIC int HTCopy ARGS4( HTStream*, sink) { HTStreamClass targetClass; + BOOL suppress_readprogress = NO; int bytes; int rv = 0; #ifdef _WINDOWS /* 1997/11/11 (Tue) 15:18:16 */ @@ -715,6 +719,16 @@ PUBLIC int HTCopy ARGS4( break; } + /* + * Suppress ReadProgress messages when collecting a redirection + * message, at least initially (unless/until anchor->content_type + * gets changed, probably by the MIME message parser). That way + * messages put up by the HTTP module or elsewhere can linger in + * the statusline for a while. - kw + */ + suppress_readprogress = (anchor && anchor->content_type && + !strcmp(anchor->content_type, + "message/x-http-redirection")); #ifdef NOT_ASCII { char * p; @@ -726,7 +740,8 @@ PUBLIC int HTCopy ARGS4( (*targetClass.put_block)(sink, input_buffer, status); bytes += status; - HTReadProgress(bytes, anchor ? anchor->content_length : 0); + if (!suppress_readprogress) + HTReadProgress(bytes, anchor ? anchor->content_length : 0); HTDisplayPartial(); } /* next bufferload */ @@ -795,7 +810,11 @@ PUBLIC int HTFileCopy ARGS2( (*targetClass.put_block)(sink, input_buffer, status); bytes += status; HTReadProgress(bytes, 0); - HTDisplayPartial(); + /* Suppress last screen update in partial mode - a regular update + * under control of mainloop() should follow anyway. - kw + */ + if (display_partial && bytes != HTMainAnchor->content_length) + HTDisplayPartial(); if (HTCheckForInterrupt()) { _HTProgress (TRANSFER_INTERRUPTED); @@ -1151,7 +1170,7 @@ PUBLIC int HTParseFile ARGS5( ** -501 Stream stack failed (cannot present or convert). ** HT_LOADED All data sent. ** -** Stat of memory and target stream on return: +** State of memory and target stream on return: ** always chunk unchanged; target freed, aborted, or NULL. */ PUBLIC int HTParseMem ARGS5( @@ -1351,3 +1370,54 @@ PUBLIC HTStream * HTNetToText ARGS1(HTStream *, sink) me->sink = sink; return me; } + +PRIVATE HTStream HTBaseStreamInstance; /* Made static */ +/* +** ERROR STREAM +** ------------ +** There is only one error stream shared by anyone who wants a +** generic error returned from all stream methods. +*/ +PRIVATE void HTErrorStream_put_character ARGS2(HTStream *, me GCC_UNUSED, char, c GCC_UNUSED) +{ + LYCancelDownload = TRUE; +} + +PRIVATE void HTErrorStream_put_string ARGS2(HTStream *, me GCC_UNUSED, CONST char *, s) +{ + if (s && *s) + LYCancelDownload = TRUE; +} + +PRIVATE void HTErrorStream_write ARGS3(HTStream *, me GCC_UNUSED, CONST char *, s, int, l) +{ + if (l && s) + LYCancelDownload = TRUE; +} + +PRIVATE void HTErrorStream_free ARGS1(HTStream *, me GCC_UNUSED) +{ + return; +} + +PRIVATE void HTErrorStream_abort ARGS2(HTStream *, me GCC_UNUSED, HTError, e GCC_UNUSED) +{ + return; +} + +PRIVATE CONST HTStreamClass HTErrorStreamClass = +{ + "ErrorStream", + HTErrorStream_free, + HTErrorStream_abort, + HTErrorStream_put_character, + HTErrorStream_put_string, + HTErrorStream_write +}; + +PUBLIC HTStream * HTErrorStream (void) +{ + CTRACE((tfp, "ErrorStream. Created\n")); + HTBaseStreamInstance.isa = &HTErrorStreamClass; /* The rest is random */ + return &HTBaseStreamInstance; +} diff --git a/WWW/Library/Implementation/HTFormat.h b/WWW/Library/Implementation/HTFormat.h index 4d119a66..a60e44ac 100644 --- a/WWW/Library/Implementation/HTFormat.h +++ b/WWW/Library/Implementation/HTFormat.h @@ -48,6 +48,14 @@ typedef HTAtom * HTFormat; */ #define WWW_PRESENT HTAtom_for("www/present") /* The user's perception */ +#define WWW_DEBUG HTAtom_for("www/debug") +/* + + WWW_DEBUG represents the user's perception of debug information, for example sent as a + HTML document in a HTTP redirection message. + + */ + /* The message/rfc822 format means a MIME message or a plain text message with no MIME @@ -57,6 +65,11 @@ typedef HTAtom * HTFormat; #define WWW_MIME HTAtom_for("www/mime") /* A MIME message */ /* + For parsing only the header. - kw + */ +#define WWW_MIME_HEAD HTAtom_for("message/x-rfc822-head") + +/* www/print is like www/present except it represents a printed copy. diff --git a/WWW/Library/Implementation/HTMIME.c b/WWW/Library/Implementation/HTMIME.c index ced1e2e9..341a2da7 100644 --- a/WWW/Library/Implementation/HTMIME.c +++ b/WWW/Library/Implementation/HTMIME.c @@ -13,6 +13,7 @@ */ #include <HTUtils.h> #include <HTMIME.h> /* Implemented here */ +#include <HTTP.h> /* for redirecting_url */ #include <HTAlert.h> #include <HTCJK.h> #include <UCMap.h> @@ -114,6 +115,9 @@ struct _HTStream { MIME_state if_ok; /* got this state if match */ MIME_state field; /* remember which field */ MIME_state fold_state; /* state on a fold */ + BOOL head_only; /* only parsing header */ + BOOL pickup_redirection; /* parsing for location */ + BOOL no_streamstack; /* use sink directly */ CONST char * check_pointer; /* checking input */ char * value_pointer; /* storing values */ @@ -125,6 +129,7 @@ struct _HTStream { char * boundary; /* For multipart */ char * set_cookie; /* Set-Cookie */ char * set_cookie2; /* Set-Cookie2 */ + char * location; /* Location */ HTFormat encoding; /* Content-Transfer-Encoding */ char * compression_encoding; @@ -161,6 +166,748 @@ PUBLIC void HTMIME_TrimDoubleQuotes ARGS1( value[i] = cp[(i +1)]; } +PRIVATE int pumpData (HTStream * me) +{ + if (strchr(HTAtom_name(me->format), ';') != NULL) { + char *cp = NULL, *cp1, *cp2, *cp3 = NULL, *cp4; + + CTRACE((tfp, "HTMIME: Extended MIME Content-Type is %s\n", + HTAtom_name(me->format))); + StrAllocCopy(cp, HTAtom_name(me->format)); + /* + ** Note that the Content-Type value was converted + ** to lower case when we loaded into me->format, + ** but there may have been a mixed or upper-case + ** atom, so we'll force lower-casing again. We + ** also stripped spaces and double-quotes, but + ** we'll make sure they're still gone from any + ** charset parameter we check. - FM + */ + LYLowerCase(cp); + if ((cp1 = strchr(cp, ';')) != NULL) { + BOOL chartrans_ok = NO; + if ((cp2 = strstr(cp1, "charset")) != NULL) { + int chndl; + + cp2 += 7; + while (*cp2 == ' ' || *cp2 == '=' || *cp2 == '\"') + cp2++; + StrAllocCopy(cp3, cp2); /* copy to mutilate more */ + for (cp4 = cp3; (*cp4 != '\0' && *cp4 != '\"' && + *cp4 != ';' && *cp4 != ':' && + !WHITE(*cp4)); cp4++) + ; /* do nothing */ + *cp4 = '\0'; + cp4 = cp3; + chndl = UCGetLYhndl_byMIME(cp3); + if (UCCanTranslateFromTo(chndl, + current_char_set)) { + chartrans_ok = YES; + *cp1 = '\0'; + me->format = HTAtom_for(cp); + StrAllocCopy(me->anchor->charset, cp4); + HTAnchor_setUCInfoStage(me->anchor, chndl, + UCT_STAGE_MIME, + UCT_SETBY_MIME); + } + else if (chndl < 0) {/* got something but we don't + recognize it */ + chndl = UCLYhndl_for_unrec; + if (chndl < 0) + /* + ** UCLYhndl_for_unrec not defined :-( + ** fallback to UCLYhndl_for_unspec + ** which always valid. + */ + chndl = UCLYhndl_for_unspec; /* always >= 0 */ + if (UCCanTranslateFromTo(chndl, + current_char_set)) { + chartrans_ok = YES; + *cp1 = '\0'; + me->format = HTAtom_for(cp); + HTAnchor_setUCInfoStage(me->anchor, chndl, + UCT_STAGE_MIME, + UCT_SETBY_DEFAULT); + } + } + if (chartrans_ok) { + LYUCcharset * p_in = + HTAnchor_getUCInfoStage(me->anchor, + UCT_STAGE_MIME); + LYUCcharset * p_out = + HTAnchor_setUCInfoStage(me->anchor, + current_char_set, + UCT_STAGE_HTEXT, + UCT_SETBY_DEFAULT); + if (!p_out) + /* + ** Try again. + */ + p_out = + HTAnchor_getUCInfoStage(me->anchor, + UCT_STAGE_HTEXT); + + if (!strcmp(p_in->MIMEname, + "x-transparent")) { + HTPassEightBitRaw = TRUE; + HTAnchor_setUCInfoStage(me->anchor, + HTAnchor_getUCLYhndl(me->anchor, + UCT_STAGE_HTEXT), + UCT_STAGE_MIME, + UCT_SETBY_DEFAULT); + } + if (!strcmp(p_out->MIMEname, + "x-transparent")) { + HTPassEightBitRaw = TRUE; + HTAnchor_setUCInfoStage(me->anchor, + HTAnchor_getUCLYhndl(me->anchor, + UCT_STAGE_MIME), + UCT_STAGE_HTEXT, + UCT_SETBY_DEFAULT); + } + if (p_in->enc != UCT_ENC_CJK) { + HTCJK = NOCJK; + if (!(p_in->codepoints & + UCT_CP_SUBSETOF_LAT1) && + chndl == current_char_set) { + HTPassEightBitRaw = TRUE; + } + } else if (p_out->enc == UCT_ENC_CJK) { + Set_HTCJK(p_in->MIMEname, p_out->MIMEname); + } + } else { + /* + ** Cannot translate. + ** If according to some heuristic the given + ** charset and the current display character + ** both are likely to be like ISO-8859 in + ** structure, pretend we have some kind + ** of match. + */ + BOOL given_is_8859 + = (BOOL) (!strncmp(cp4, "iso-8859-", 9) && + isdigit((unsigned char)cp4[9])); + BOOL given_is_8859like + = (BOOL) (given_is_8859 || + !strncmp(cp4, "windows-", 8) || + !strncmp(cp4, "cp12", 4) || + !strncmp(cp4, "cp-12", 5)); + BOOL given_and_display_8859like + = (BOOL) (given_is_8859like && + (strstr(LYchar_set_names[current_char_set], + "ISO-8859") || + strstr(LYchar_set_names[current_char_set], + "windows-"))); + + if (given_and_display_8859like) { + *cp1 = '\0'; + me->format = HTAtom_for(cp); + } + if (given_is_8859) { + cp1 = &cp4[10]; + while (*cp1 && + isdigit((unsigned char)(*cp1))) + cp1++; + *cp1 = '\0'; + } + if (given_and_display_8859like) { + StrAllocCopy(me->anchor->charset, cp4); + HTPassEightBitRaw = TRUE; + } + HTAlert(*cp4 ? cp4 : me->anchor->charset); + } + FREE(cp3); + } else { + /* + ** No charset parameter is present. + ** Ignore all other parameters, as + ** we do when charset is present. - FM + */ + *cp1 = '\0'; + me->format = HTAtom_for(cp); + } + } + FREE(cp); + } + /* + ** If we have an Expires header and haven't + ** already set the no_cache element for the + ** anchor, check if we should set it based + ** on that header. - FM + */ + if (me->anchor->no_cache == FALSE && + me->anchor->expires != NULL) { + if (!strcmp(me->anchor->expires, "0")) { + /* + * The value is zero, which we treat as + * an absolute no-cache directive. - FM + */ + me->anchor->no_cache = TRUE; + } else if (me->anchor->date != NULL) { + /* + ** We have a Date header, so check if + ** the value is less than or equal to + ** that. - FM + */ + if (LYmktime(me->anchor->expires, TRUE) <= + LYmktime(me->anchor->date, TRUE)) { + me->anchor->no_cache = TRUE; + } + } else if (LYmktime(me->anchor->expires, FALSE) <= 0) { + /* + ** We don't have a Date header, and + ** the value is in past for us. - FM + */ + me->anchor->no_cache = TRUE; + } + } + StrAllocCopy(me->anchor->content_type, + HTAtom_name(me->format)); + + if (me->set_cookie != NULL || me->set_cookie2 != NULL) { + LYSetCookie(me->set_cookie, + me->set_cookie2, + me->anchor->address); + FREE(me->set_cookie); + FREE(me->set_cookie2); + } + if (me->pickup_redirection) { + if (me->location && *me->location) { + redirecting_url = me->location; + me->location = NULL; + if (me->targetRep != WWW_DEBUG || me->sink) + me->head_only = YES; + + } else { + permanent_redirection = FALSE; + if (me->location) { + CTRACE((tfp, "HTTP: 'Location:' is zero-length!\n")); + HTAlert( + gettext("Got redirection with a bad Location header.")); + } + CTRACE((tfp, "HTTP: Failed to pick up location.\n")); + if (me->location) { + FREE(me->location); + } else { + HTAlert(gettext("Got redirection with no Location header.")); + } + } + } + if (me->head_only) { + /* We are done! - kw */ + me->state = MIME_IGNORE; + return HT_OK; + } + + if (me->no_streamstack) { + me->target = me->sink; + } else { + if (!me->compression_encoding) { + CTRACE((tfp, "HTMIME: MIME Content-Type is '%s', converting to '%s'\n", + HTAtom_name(me->format), HTAtom_name(me->targetRep))); + } else { + /* + ** Change the format to that for "www/compressed" + ** and set up a stream to deal with it. - FM + */ + CTRACE((tfp, "HTMIME: MIME Content-Type is '%s',\n", HTAtom_name(me->format))); + me->format = HTAtom_for("www/compressed"); + CTRACE((tfp, " Treating as '%s'. Converting to '%s'\n", + HTAtom_name(me->format), HTAtom_name(me->targetRep))); + FREE(me->compression_encoding); + } + me->target = HTStreamStack(me->format, me->targetRep, + me->sink , me->anchor); + if (!me->target) { + CTRACE((tfp, "HTMIME: 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, + ** someday, but until we have the relevant code, + ** from now push straight through. - FM + */ + me->state = MIME_TRANSPARENT; /* Pump rest of data right through */ + } else { + me->state = MIME_IGNORE; /* What else to do? */ + } + return HT_OK; +} + +PRIVATE int dispatchField (HTStream * me) +{ + int i, j; + char *cp; + + *me->value_pointer = '\0'; + cp = me->value_pointer; + while ((cp > me->value) && *(--cp) == ' ') /* S/390 -- gil -- 0146 */ + /* + ** Trim trailing spaces. + */ + *cp = '\0'; + + switch (me->field) { + case miACCEPT_RANGES: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Accept-Ranges: '%s'\n", + me->value)); + break; + case miAGE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Age: '%s'\n", + me->value)); + break; + case miALLOW: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Allow: '%s'\n", + me->value)); + break; + case miALTERNATES: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Alternates: '%s'\n", + me->value)); + break; + case miCACHE_CONTROL: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Cache-Control: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Convert to lowercase and indicate in anchor. - FM + */ + LYLowerCase(me->value); + StrAllocCopy(me->anchor->cache_control, me->value); + /* + ** Check whether to set no_cache for the anchor. - FM + */ + { + char *cp1, *cp0 = me->value; + + while ((cp1 = strstr(cp0, "no-cache")) != NULL) { + cp1 += 8; + while (*cp1 != '\0' && WHITE(*cp1)) + cp1++; + if (*cp1 == '\0' || *cp1 == ';') { + me->anchor->no_cache = TRUE; + break; + } + cp0 = cp1; + } + if (me->anchor->no_cache == TRUE) + break; + cp0 = me->value; + while ((cp1 = strstr(cp0, "max-age")) != NULL) { + cp1 += 7; + while (*cp1 != '\0' && WHITE(*cp1)) + cp1++; + if (*cp1 == '=') { + cp1++; + while (*cp1 != '\0' && WHITE(*cp1)) + cp1++; + if (isdigit((unsigned char)*cp1)) { + cp0 = cp1; + while (isdigit((unsigned char)*cp1)) + cp1++; + if (*cp0 == '0' && cp1 == (cp0 + 1)) { + me->anchor->no_cache = TRUE; + break; + } + } + } + cp0 = cp1; + } + } + break; + case miCOOKIE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Cookie: '%s'\n", + me->value)); + break; + case miCONNECTION: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Connection: '%s'\n", + me->value)); + break; + case miCONTENT_BASE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-Base: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->content_base, me->value); + break; + case miCONTENT_DISPOSITION: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-Disposition: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->content_disposition, me->value); + /* + ** It's not clear yet from existing RFCs and IDs + ** whether we should be looking for file;, attachment;, + ** and/or inline; before the filename=value, so we'll + ** just search for "filename" followed by '=' and just + ** hope we get the intended value. It is purely a + ** suggested name, anyway. - FM + */ + cp = me->anchor->content_disposition; + while (*cp != '\0' && strncasecomp(cp, "filename", 8)) + cp++; + if (*cp == '\0') + break; + cp += 8; + while ((*cp != '\0') && (WHITE(*cp) || *cp == '=')) + cp++; + if (*cp == '\0') + break; + while (*cp != '\0' && WHITE(*cp)) + cp++; + if (*cp == '\0') + break; + StrAllocCopy(me->anchor->SugFname, cp); + if (*me->anchor->SugFname == '\"') { + if ((cp = strchr((me->anchor->SugFname + 1), + '\"')) != NULL) { + *(cp + 1) = '\0'; + HTMIME_TrimDoubleQuotes(me->anchor->SugFname); + } else { + FREE(me->anchor->SugFname); + break; + } + } + cp = me->anchor->SugFname; + while (*cp != '\0' && !WHITE(*cp)) + cp++; + *cp = '\0'; + if (*me->anchor->SugFname == '\0') + FREE(me->anchor->SugFname); + break; + case miCONTENT_ENCODING: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-Encoding: '%s'\n", + me->value)); + if (!(me->value && *me->value) || + !strcasecomp(me->value, "identity")) + break; + /* + ** Convert to lowercase and indicate in anchor. - FM + */ + LYLowerCase(me->value); + StrAllocCopy(me->anchor->content_encoding, me->value); + FREE(me->compression_encoding); + if (!strcmp(me->value, "8bit") || + !strcmp(me->value, "7bit") || + !strcmp(me->value, "binary")) { + /* + ** Some server indicated "8bit", "7bit" or "binary" + ** inappropriately. We'll ignore it. - FM + */ + CTRACE((tfp, " Ignoring it!\n")); + } else { + /* + ** Save it to use as a flag for setting + ** up a "www/compressed" target. - FM + */ + StrAllocCopy(me->compression_encoding, me->value); + } + break; + case miCONTENT_FEATURES: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-Features: '%s'\n", + me->value)); + break; + case miCONTENT_LANGUAGE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-Language: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Convert to lowercase and indicate in anchor. - FM + */ + LYLowerCase(me->value); + StrAllocCopy(me->anchor->content_language, me->value); + break; + case miCONTENT_LENGTH: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-Length: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Convert to integer and indicate in anchor. - FM + */ + me->anchor->content_length = atoi(me->value); + if (me->anchor->content_length < 0) + me->anchor->content_length = 0; + CTRACE((tfp, " Converted to integer: '%d'\n", + me->anchor->content_length)); + break; + case miCONTENT_LOCATION: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-Location: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->content_location, me->value); + break; + case miCONTENT_MD5: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-MD5: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->content_md5, me->value); + break; + case miCONTENT_RANGE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-Range: '%s'\n", + me->value)); + break; + case miCONTENT_TRANSFER_ENCODING: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-Transfer-Encoding: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Force the Content-Transfer-Encoding value + ** to all lower case. - FM + */ + LYLowerCase(me->value); + me->encoding = HTAtom_for(me->value); + break; + case miCONTENT_TYPE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Content-Type: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Force the Content-Type value to all lower case + ** and strip spaces and double-quotes. - FM + */ + for (i = 0, j = 0; me->value[i]; i++) { + if (me->value[i] != ' ' && me->value[i] != '\"') { + me->value[j++] = (char) TOLOWER(me->value[i]); + } + } + me->value[j] = '\0'; + me->format = HTAtom_for(me->value); + break; + case miDATE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Date: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->date, me->value); + break; + case miETAG: + /* Do not trim double quotes: + * an entity tag consists of an opaque quoted string, + * possibly prefixed by a weakness indicator. + */ + CTRACE((tfp, "HTMIME: PICKED UP ETag: %s\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->ETag, me->value); + break; + case miEXPIRES: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Expires: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->expires, me->value); + break; + case miKEEP_ALIVE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Keep-Alive: '%s'\n", + me->value)); + break; + case miLAST_MODIFIED: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Last-Modified: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->last_modified, me->value); + break; + case miLINK: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Link: '%s'\n", + me->value)); + break; + case miLOCATION: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Location: '%s'\n", + me->value)); + if (me->pickup_redirection && !me->location) { + StrAllocCopy(me->location, me->value); + } else { + CTRACE((tfp, "HTMIME: *** Ignoring Location!\n")); + } + break; + case miPRAGMA: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Pragma: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Check whether to set no_cache for the anchor. - FM + */ + if (!strcmp(me->value, "no-cache")) + me->anchor->no_cache = TRUE; + break; + case miPROXY_AUTHENTICATE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Proxy-Authenticate: '%s'\n", + me->value)); + break; + case miPUBLIC: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Public: '%s'\n", + me->value)); + break; + case miRETRY_AFTER: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Retry-After: '%s'\n", + me->value)); + break; + case miSAFE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Safe: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor if "YES" or "TRUE". - FM + */ + if (!strcasecomp(me->value, "YES") || + !strcasecomp(me->value, "TRUE")) { + me->anchor->safe = TRUE; + } else if (!strcasecomp(me->value, "NO") || + !strcasecomp(me->value, "FALSE")) { + /* + ** If server explicitly tells us that it has changed + ** its mind, reset flag in anchor. - kw + */ + me->anchor->safe = FALSE; + } + break; + case miSERVER: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Server: '%s'\n", + me->value)); + if (!(me->value && *me->value)) + break; + /* + ** Indicate in anchor. - FM + */ + StrAllocCopy(me->anchor->server, me->value); + break; + case miSET_COOKIE1: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Set-Cookie: '%s'\n", + me->value)); + if (me->set_cookie == NULL) { + StrAllocCopy(me->set_cookie, me->value); + } else { + StrAllocCat(me->set_cookie, ", "); + StrAllocCat(me->set_cookie, me->value); + } + break; + case miSET_COOKIE2: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Set-Cookie2: '%s'\n", + me->value)); + if (me->set_cookie2 == NULL) { + StrAllocCopy(me->set_cookie2, me->value); + } else { + StrAllocCat(me->set_cookie2, ", "); + StrAllocCat(me->set_cookie2, me->value); + } + break; + case miTITLE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Title: '%s'\n", + me->value)); + break; + case miTRANSFER_ENCODING: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Transfer-Encoding: '%s'\n", + me->value)); + break; + case miUPGRADE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Upgrade: '%s'\n", + me->value)); + break; + case miURI: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP URI: '%s'\n", + me->value)); + break; + case miVARY: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Vary: '%s'\n", + me->value)); + break; + case miVIA: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Via: '%s'\n", + me->value)); + break; + case miWARNING: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP Warning: '%s'\n", + me->value)); + break; + case miWWW_AUTHENTICATE: + HTMIME_TrimDoubleQuotes(me->value); + CTRACE((tfp, "HTMIME: PICKED UP WWW-Authenticate: '%s'\n", + me->value)); + break; + default: /* Should never get here */ + return HT_ERROR; + } + return HT_OK; +} + + /*_________________________________________________________________________ ** ** A C T I O N R O U T I N E S @@ -169,16 +916,15 @@ PUBLIC void HTMIME_TrimDoubleQuotes ARGS1( /* Character handling ** ------------------ ** -** This is a FSM parser which is tolerant as it can be of all -** syntax errors. It ignores field names it does not understand, -** and resynchronises on line beginnings. +** This is a FSM parser. It ignores field names it does not understand. +** Folded header fields are recognized. Lines without a fieldname at +** the beginning (that are not folded continuation lines) are ignored +** as unknown field names. Fields with empty values are not picked up. */ PRIVATE void HTMIME_put_character ARGS2( HTStream *, me, char, c) { - int i, j; - if (me->state == MIME_TRANSPARENT) { (*me->targetClass.put_character)(me->target, c);/* MUST BE FAST */ return; @@ -223,7 +969,17 @@ PRIVATE void HTMIME_put_character ARGS2( case miNEWLINE: if (c != '\n' && WHITE(c)) { /* Folded line */ me->state = me->fold_state; /* pop state before newline */ + if (me->state == miGET_VALUE && + me->value_pointer && me->value_pointer != me->value && + !WHITE(*(me->value_pointer-1))) { + c = ' '; + goto GET_VALUE; /* will add space to value if it fits - kw */ + } break; + } else if (me->fold_state == miGET_VALUE) { + /* Got a field, and now we know it's complete - so + * act on it. - kw */ + dispatchField(me); } /* else Falls through */ @@ -318,239 +1074,7 @@ PRIVATE void HTMIME_put_character ARGS2( case '\n': /* Blank line: End of Header! */ { me->net_ascii = NO; - if (strchr(HTAtom_name(me->format), ';') != NULL) { - char *cp = NULL, *cp1, *cp2, *cp3 = NULL, *cp4; - - CTRACE((tfp, "HTMIME: Extended MIME Content-Type is %s\n", - HTAtom_name(me->format))); - StrAllocCopy(cp, HTAtom_name(me->format)); - /* - ** Note that the Content-Type value was converted - ** to lower case when we loaded into me->format, - ** but there may have been a mixed or upper-case - ** atom, so we'll force lower-casing again. We - ** also stripped spaces and double-quotes, but - ** we'll make sure they're still gone from any - ** charset parameter we check. - FM - */ - LYLowerCase(cp); - if ((cp1 = strchr(cp, ';')) != NULL) { - BOOL chartrans_ok = NO; - if ((cp2 = strstr(cp1, "charset")) != NULL) { - int chndl; - - cp2 += 7; - while (*cp2 == ' ' || *cp2 == '=' || *cp2 == '\"') - cp2++; - StrAllocCopy(cp3, cp2); /* copy to mutilate more */ - for (cp4 = cp3; (*cp4 != '\0' && *cp4 != '\"' && - *cp4 != ';' && *cp4 != ':' && - !WHITE(*cp4)); cp4++) - ; /* do nothing */ - *cp4 = '\0'; - cp4 = cp3; - chndl = UCGetLYhndl_byMIME(cp3); - if (UCCanTranslateFromTo(chndl, - current_char_set)) { - chartrans_ok = YES; - *cp1 = '\0'; - me->format = HTAtom_for(cp); - StrAllocCopy(me->anchor->charset, cp4); - HTAnchor_setUCInfoStage(me->anchor, chndl, - UCT_STAGE_MIME, - UCT_SETBY_MIME); - } - else if (chndl < 0) {/* got something but we don't - recognize it */ - chndl = UCLYhndl_for_unrec; - if (chndl < 0) - /* - ** UCLYhndl_for_unrec not defined :-( - ** fallback to UCLYhndl_for_unspec - ** which always valid. - */ - chndl = UCLYhndl_for_unspec; /* always >= 0 */ - if (UCCanTranslateFromTo(chndl, - current_char_set)) { - chartrans_ok = YES; - *cp1 = '\0'; - me->format = HTAtom_for(cp); - HTAnchor_setUCInfoStage(me->anchor, chndl, - UCT_STAGE_MIME, - UCT_SETBY_DEFAULT); - } - } - if (chartrans_ok) { - LYUCcharset * p_in = - HTAnchor_getUCInfoStage(me->anchor, - UCT_STAGE_MIME); - LYUCcharset * p_out = - HTAnchor_setUCInfoStage(me->anchor, - current_char_set, - UCT_STAGE_HTEXT, - UCT_SETBY_DEFAULT); - if (!p_out) - /* - ** Try again. - */ - p_out = - HTAnchor_getUCInfoStage(me->anchor, - UCT_STAGE_HTEXT); - - if (!strcmp(p_in->MIMEname, - "x-transparent")) { - HTPassEightBitRaw = TRUE; - HTAnchor_setUCInfoStage(me->anchor, - HTAnchor_getUCLYhndl(me->anchor, - UCT_STAGE_HTEXT), - UCT_STAGE_MIME, - UCT_SETBY_DEFAULT); - } - if (!strcmp(p_out->MIMEname, - "x-transparent")) { - HTPassEightBitRaw = TRUE; - HTAnchor_setUCInfoStage(me->anchor, - HTAnchor_getUCLYhndl(me->anchor, - UCT_STAGE_MIME), - UCT_STAGE_HTEXT, - UCT_SETBY_DEFAULT); - } - if (p_in->enc != UCT_ENC_CJK) { - HTCJK = NOCJK; - if (!(p_in->codepoints & - UCT_CP_SUBSETOF_LAT1) && - chndl == current_char_set) { - HTPassEightBitRaw = TRUE; - } - } else if (p_out->enc == UCT_ENC_CJK) { - Set_HTCJK(p_in->MIMEname, p_out->MIMEname); - } - } else { - /* - ** Cannot translate. - ** If according to some heuristic the given - ** charset and the current display character - ** both are likely to be like ISO-8859 in - ** structure, pretend we have some kind - ** of match. - */ - BOOL given_is_8859 - = (BOOL) (!strncmp(cp4, "iso-8859-", 9) && - isdigit((unsigned char)cp4[9])); - BOOL given_is_8859like - = (BOOL) (given_is_8859 || - !strncmp(cp4, "windows-", 8) || - !strncmp(cp4, "cp12", 4) || - !strncmp(cp4, "cp-12", 5)); - BOOL given_and_display_8859like - = (BOOL) (given_is_8859like && - (strstr(LYchar_set_names[current_char_set], - "ISO-8859") || - strstr(LYchar_set_names[current_char_set], - "windows-"))); - - if (given_and_display_8859like) { - *cp1 = '\0'; - me->format = HTAtom_for(cp); - } - if (given_is_8859) { - cp1 = &cp4[10]; - while (*cp1 && - isdigit((unsigned char)(*cp1))) - cp1++; - *cp1 = '\0'; - } - if (given_and_display_8859like) { - StrAllocCopy(me->anchor->charset, cp4); - HTPassEightBitRaw = TRUE; - } - HTAlert(*cp4 ? cp4 : me->anchor->charset); - } - FREE(cp3); - } else { - /* - ** No charset parameter is present. - ** Ignore all other parameters, as - ** we do when charset is present. - FM - */ - *cp1 = '\0'; - me->format = HTAtom_for(cp); - } - } - FREE(cp); - } - /* - ** If we have an Expires header and haven't - ** already set the no_cache element for the - ** anchor, check if we should set it based - ** on that header. - FM - */ - if (me->anchor->no_cache == FALSE && - me->anchor->expires != NULL) { - if (!strcmp(me->anchor->expires, "0")) { - /* - * The value is zero, which we treat as - * an absolute no-cache directive. - FM - */ - me->anchor->no_cache = TRUE; - } else if (me->anchor->date != NULL) { - /* - ** We have a Date header, so check if - ** the value is less than or equal to - ** that. - FM - */ - if (LYmktime(me->anchor->expires, TRUE) <= - LYmktime(me->anchor->date, TRUE)) { - me->anchor->no_cache = TRUE; - } - } else if (LYmktime(me->anchor->expires, FALSE) <= 0) { - /* - ** We don't have a Date header, and - ** the value is in past for us. - FM - */ - me->anchor->no_cache = TRUE; - } - } - StrAllocCopy(me->anchor->content_type, - HTAtom_name(me->format)); - if (!me->compression_encoding) { - CTRACE((tfp, "HTMIME: MIME Content-Type is '%s', converting to '%s'\n", - HTAtom_name(me->format), HTAtom_name(me->targetRep))); - } else { - /* - ** Change the format to that for "www/compressed" - ** and set up a stream to deal with it. - FM - */ - CTRACE((tfp, "HTMIME: MIME Content-Type is '%s',\n", HTAtom_name(me->format))); - me->format = HTAtom_for("www/compressed"); - CTRACE((tfp, " Treating as '%s'. Converting to '%s'\n", - HTAtom_name(me->format), HTAtom_name(me->targetRep))); - } - if (me->set_cookie != NULL || me->set_cookie2 != NULL) { - LYSetCookie(me->set_cookie, - me->set_cookie2, - me->anchor->address); - FREE(me->set_cookie); - FREE(me->set_cookie2); - } - me->target = HTStreamStack(me->format, me->targetRep, - me->sink , me->anchor); - if (!me->target) { - CTRACE((tfp, "HTMIME: 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, - ** someday, but until we have the relevant code, - ** from now push straight through. - FM - */ - me->state = MIME_TRANSPARENT; - } else { - me->state = MIME_IGNORE; /* What else to do? */ - } - FREE(me->compression_encoding); + pumpData(me); } break; @@ -1170,9 +1694,9 @@ PRIVATE void HTMIME_put_character ARGS2( case miSKIP_GET_VALUE: if (c == '\n') { - me->fold_state = me->state; - me->state = miNEWLINE; - break; + me->fold_state = me->state; + me->state = miNEWLINE; + break; } if (WHITE(c)) /* @@ -1185,465 +1709,8 @@ PRIVATE void HTMIME_put_character ARGS2( /* Fall through to store first character */ case miGET_VALUE: - if (WHITE(c) && c != ' ') { /* End of field */ - char *cp; - *me->value_pointer = '\0'; - cp = (me->value_pointer - 1); - while ((cp >= me->value) && *cp == ' ') /* S/390 -- gil -- 0146 */ - /* - ** Trim trailing spaces. - */ - *cp = '\0'; - switch (me->field) { - case miACCEPT_RANGES: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Accept-Ranges: '%s'\n", - me->value)); - break; - case miAGE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Age: '%s'\n", - me->value)); - break; - case miALLOW: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Allow: '%s'\n", - me->value)); - break; - case miALTERNATES: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Alternates: '%s'\n", - me->value)); - break; - case miCACHE_CONTROL: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Cache-Control: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Convert to lowercase and indicate in anchor. - FM - */ - LYLowerCase(me->value); - StrAllocCopy(me->anchor->cache_control, me->value); - /* - ** Check whether to set no_cache for the anchor. - FM - */ - { - char *cp1, *cp0 = me->value; - - while ((cp1 = strstr(cp0, "no-cache")) != NULL) { - cp1 += 8; - while (*cp1 != '\0' && WHITE(*cp1)) - cp1++; - if (*cp1 == '\0' || *cp1 == ';') { - me->anchor->no_cache = TRUE; - break; - } - cp0 = cp1; - } - if (me->anchor->no_cache == TRUE) - break; - cp0 = me->value; - while ((cp1 = strstr(cp0, "max-age")) != NULL) { - cp1 += 7; - while (*cp1 != '\0' && WHITE(*cp1)) - cp1++; - if (*cp1 == '=') { - cp1++; - while (*cp1 != '\0' && WHITE(*cp1)) - cp1++; - if (isdigit((unsigned char)*cp1)) { - cp0 = cp1; - while (isdigit((unsigned char)*cp1)) - cp1++; - if (*cp0 == '0' && cp1 == (cp0 + 1)) { - me->anchor->no_cache = TRUE; - break; - } - } - } - cp0 = cp1; - } - } - break; - case miCOOKIE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Cookie: '%s'\n", - me->value)); - break; - case miCONNECTION: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Connection: '%s'\n", - me->value)); - break; - case miCONTENT_BASE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-Base: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Indicate in anchor. - FM - */ - StrAllocCopy(me->anchor->content_base, me->value); - break; - case miCONTENT_DISPOSITION: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-Disposition: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Indicate in anchor. - FM - */ - StrAllocCopy(me->anchor->content_disposition, me->value); - /* - ** It's not clear yet from existing RFCs and IDs - ** whether we should be looking for file;, attachment;, - ** and/or inline; before the filename=value, so we'll - ** just search for "filename" followed by '=' and just - ** hope we get the intended value. It is purely a - ** suggested name, anyway. - FM - */ - cp = me->anchor->content_disposition; - while (*cp != '\0' && strncasecomp(cp, "filename", 8)) - cp++; - if (*cp == '\0') - break; - cp += 8; - while ((*cp != '\0') && (WHITE(*cp) || *cp == '=')) - cp++; - if (*cp == '\0') - break; - while (*cp != '\0' && WHITE(*cp)) - cp++; - if (*cp == '\0') - break; - StrAllocCopy(me->anchor->SugFname, cp); - if (*me->anchor->SugFname == '\"') { - if ((cp = strchr((me->anchor->SugFname + 1), - '\"')) != NULL) { - *(cp + 1) = '\0'; - HTMIME_TrimDoubleQuotes(me->anchor->SugFname); - } else { - FREE(me->anchor->SugFname); - break; - } - } - cp = me->anchor->SugFname; - while (*cp != '\0' && !WHITE(*cp)) - cp++; - *cp = '\0'; - if (*me->anchor->SugFname == '\0') - FREE(me->anchor->SugFname); - break; - case miCONTENT_ENCODING: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-Encoding: '%s'\n", - me->value)); - if (!(me->value && *me->value) || - !strcasecomp(me->value, "identity")) - break; - /* - ** Convert to lowercase and indicate in anchor. - FM - */ - LYLowerCase(me->value); - StrAllocCopy(me->anchor->content_encoding, me->value); - FREE(me->compression_encoding); - if (!strcmp(me->value, "8bit") || - !strcmp(me->value, "7bit") || - !strcmp(me->value, "binary")) { - /* - ** Some server indicated "8bit", "7bit" or "binary" - ** inappropriately. We'll ignore it. - FM - */ - CTRACE((tfp, " Ignoring it!\n")); - } else { - /* - ** Save it to use as a flag for setting - ** up a "www/compressed" target. - FM - */ - StrAllocCopy(me->compression_encoding, me->value); - } - break; - case miCONTENT_FEATURES: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-Features: '%s'\n", - me->value)); - break; - case miCONTENT_LANGUAGE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-Language: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Convert to lowercase and indicate in anchor. - FM - */ - LYLowerCase(me->value); - StrAllocCopy(me->anchor->content_language, me->value); - break; - case miCONTENT_LENGTH: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-Length: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Convert to integer and indicate in anchor. - FM - */ - me->anchor->content_length = atoi(me->value); - if (me->anchor->content_length < 0) - me->anchor->content_length = 0; - CTRACE((tfp, " Converted to integer: '%d'\n", - me->anchor->content_length)); - break; - case miCONTENT_LOCATION: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-Location: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Indicate in anchor. - FM - */ - StrAllocCopy(me->anchor->content_location, me->value); - break; - case miCONTENT_MD5: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-MD5: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Indicate in anchor. - FM - */ - StrAllocCopy(me->anchor->content_md5, me->value); - break; - case miCONTENT_RANGE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-Range: '%s'\n", - me->value)); - break; - case miCONTENT_TRANSFER_ENCODING: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-Transfer-Encoding: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Force the Content-Transfer-Encoding value - ** to all lower case. - FM - */ - LYLowerCase(me->value); - me->encoding = HTAtom_for(me->value); - break; - case miCONTENT_TYPE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Content-Type: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Force the Content-Type value to all lower case - ** and strip spaces and double-quotes. - FM - */ - for (i = 0, j = 0; me->value[i]; i++) { - if (me->value[i] != ' ' && me->value[i] != '\"') { - me->value[j++] = (char) TOLOWER(me->value[i]); - } - } - me->value[j] = '\0'; - me->format = HTAtom_for(me->value); - break; - case miDATE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Date: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Indicate in anchor. - FM - */ - StrAllocCopy(me->anchor->date, me->value); - break; - case miETAG: - /* Do not trim double quotes: - * an entity tag consists of an opaque quoted string, - * possibly prefixed by a weakness indicator. - */ - CTRACE((tfp, "HTMIME: PICKED UP ETag: %s\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Indicate in anchor. - FM - */ - StrAllocCopy(me->anchor->ETag, me->value); - break; - case miEXPIRES: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Expires: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Indicate in anchor. - FM - */ - StrAllocCopy(me->anchor->expires, me->value); - break; - case miKEEP_ALIVE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Keep-Alive: '%s'\n", - me->value)); - break; - case miLAST_MODIFIED: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Last-Modified: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Indicate in anchor. - FM - */ - StrAllocCopy(me->anchor->last_modified, me->value); - break; - case miLINK: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Link: '%s'\n", - me->value)); - break; - case miLOCATION: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Location: '%s'\n", - me->value)); - break; - case miPRAGMA: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Pragma: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Check whether to set no_cache for the anchor. - FM - */ - if (!strcmp(me->value, "no-cache")) - me->anchor->no_cache = TRUE; - break; - case miPROXY_AUTHENTICATE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Proxy-Authenticate: '%s'\n", - me->value)); - break; - case miPUBLIC: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Public: '%s'\n", - me->value)); - break; - case miRETRY_AFTER: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Retry-After: '%s'\n", - me->value)); - break; - case miSAFE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Safe: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Indicate in anchor if "YES" or "TRUE". - FM - */ - if (!strcasecomp(me->value, "YES") || - !strcasecomp(me->value, "TRUE")) { - me->anchor->safe = TRUE; - } else if (!strcasecomp(me->value, "NO") || - !strcasecomp(me->value, "FALSE")) { - /* - ** If server explicitly tells us that it has changed - ** its mind, reset flag in anchor. - kw - */ - me->anchor->safe = FALSE; - } - break; - case miSERVER: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Server: '%s'\n", - me->value)); - if (!(me->value && *me->value)) - break; - /* - ** Indicate in anchor. - FM - */ - StrAllocCopy(me->anchor->server, me->value); - break; - case miSET_COOKIE1: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Set-Cookie: '%s'\n", - me->value)); - if (me->set_cookie == NULL) { - StrAllocCopy(me->set_cookie, me->value); - } else { - StrAllocCat(me->set_cookie, ", "); - StrAllocCat(me->set_cookie, me->value); - } - break; - case miSET_COOKIE2: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Set-Cookie2: '%s'\n", - me->value)); - if (me->set_cookie2 == NULL) { - StrAllocCopy(me->set_cookie2, me->value); - } else { - StrAllocCat(me->set_cookie2, ", "); - StrAllocCat(me->set_cookie2, me->value); - } - break; - case miTITLE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Title: '%s'\n", - me->value)); - break; - case miTRANSFER_ENCODING: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Transfer-Encoding: '%s'\n", - me->value)); - break; - case miUPGRADE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Upgrade: '%s'\n", - me->value)); - break; - case miURI: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP URI: '%s'\n", - me->value)); - break; - case miVARY: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Vary: '%s'\n", - me->value)); - break; - case miVIA: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Via: '%s'\n", - me->value)); - break; - case miWARNING: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP Warning: '%s'\n", - me->value)); - break; - case miWWW_AUTHENTICATE: - HTMIME_TrimDoubleQuotes(me->value); - CTRACE((tfp, "HTMIME: PICKED UP WWW-Authenticate: '%s'\n", - me->value)); - break; - default: /* Should never get here */ - break; - } - } else { + GET_VALUE: + if (c != '\n') { /* Not end of line */ if (me->value_pointer < me->value + VALUE_SIZE - 1) { *me->value_pointer++ = c; break; @@ -1651,12 +1718,12 @@ PRIVATE void HTMIME_put_character ARGS2( goto value_too_long; } } - /* Fall through */ + /* Fall through (if end of line) */ case miJUNK_LINE: if (c == '\n') { - me->state = miNEWLINE; me->fold_state = me->state; + me->state = miNEWLINE; } break; @@ -1728,9 +1795,13 @@ PRIVATE void HTMIME_write ARGS3( PRIVATE void HTMIME_free ARGS1( HTStream *, me) { - if (me->target) - (*me->targetClass._free)(me->target); - FREE(me); + if (me) { + FREE(me->location); + FREE(me->compression_encoding); + if (me->target) + (*me->targetClass._free)(me->target); + FREE(me); + } } /* End writing @@ -1739,9 +1810,13 @@ PRIVATE void HTMIME_abort ARGS2( HTStream *, me, HTError, e) { - if (me->target) - (*me->targetClass._abort)(me->target, e); - FREE(me); + if (me) { + FREE(me->location); + FREE(me->compression_encoding); + if (me->target) + (*me->targetClass._abort)(me->target, e); + FREE(me); + } } @@ -1844,6 +1919,21 @@ PUBLIC HTStream* HTNetMIME ARGS3( return me; } +PUBLIC HTStream* HTMIMERedirect ARGS3( + HTPresentation *, pres, + HTParentAnchor *, anchor, + HTStream *, sink) +{ + HTStream* me = HTMIMEConvert(pres,anchor, sink); + if (!me) + return NULL; + + me->pickup_redirection = YES; + if (me->targetRep == WWW_DEBUG && sink) + me->no_streamstack = YES; + return me; +} + /* Japanese header handling functions ** ================================== ** diff --git a/WWW/Library/Implementation/HTMIME.h b/WWW/Library/Implementation/HTMIME.h index 25c28660..818f38f2 100644 --- a/WWW/Library/Implementation/HTMIME.h +++ b/WWW/Library/Implementation/HTMIME.h @@ -52,6 +52,14 @@ extern HTStream * HTMIMEConvert PARAMS((HTPresentation * pres, extern HTStream * HTNetMIME PARAMS((HTPresentation * pres, HTParentAnchor * anchor, HTStream * sink)); +/* + + INPUT: Redirection message, parse headers only for Location if present + + */ +extern HTStream * HTMIMERedirect PARAMS((HTPresentation * pres, + HTParentAnchor * anchor, + HTStream * sink)); /* diff --git a/WWW/Library/Implementation/HTParse.c b/WWW/Library/Implementation/HTParse.c index 9363fa55..8a4a9ede 100644 --- a/WWW/Library/Implementation/HTParse.c +++ b/WWW/Library/Implementation/HTParse.c @@ -824,21 +824,17 @@ PUBLIC char * HTUnEscape ARGS1( p[1] && p[2] && isxdigit((unsigned char)p[1]) && isxdigit((unsigned char)p[2])) { - if (iscntrl(FROMASCII(from_hex(p[1])*16 + from_hex(p[2])))) { - *q++ = *p++; /* Ignore control codes. --HN [98/09/08] */ - } else { - p++; - if (*p) - *q = (char) (from_hex(*p++) * 16); - if (*p) { - /* - ** Careful! FROMASCII() may evaluate its arg more than once! - */ /* S/390 -- gil -- 0221 */ - *q = (char) (*q + from_hex(*p++)); - } - *q = FROMASCII(*q); - q++; - } + p++; + if (*p) + *q = (char) (from_hex(*p++) * 16); + if (*p) { + /* + ** Careful! FROMASCII() may evaluate its arg more than once! + */ /* S/390 -- gil -- 0221 */ + *q = (char) (*q + from_hex(*p++)); + } + *q = FROMASCII(*q); + q++; } else { *q++ = *p++; } diff --git a/WWW/Library/Implementation/HTStream.h b/WWW/Library/Implementation/HTStream.h index dd18e40b..a9c4703d 100644 --- a/WWW/Library/Implementation/HTStream.h +++ b/WWW/Library/Implementation/HTStream.h @@ -54,6 +54,17 @@ typedef struct _HTStreamClass { }HTStreamClass; +/* + + Generic Error Stream + + The Error stream simply signals an error on all output methods. + This can be used to stop a stream as soon as data arrives, for + example from the network. + + */ +extern HTStream * HTErrorStream (void); + #endif /* HTSTREAM_H */ /* diff --git a/WWW/Library/Implementation/HTTP.c b/WWW/Library/Implementation/HTTP.c index 3e39dee7..68797904 100644 --- a/WWW/Library/Implementation/HTTP.c +++ b/WWW/Library/Implementation/HTTP.c @@ -295,7 +295,8 @@ PRIVATE int HTLoadHTTP ARGS4 ( BOOL auth_proxy = NO; /* Generate a proxy authorization. - AJL */ int length, rawlength, rv; - BOOL doing_redirect, already_retrying = FALSE, bad_location = FALSE; + int server_status; + BOOL doing_redirect, already_retrying = FALSE; int len = 0; void * handle = NULL; @@ -993,7 +994,6 @@ try_again: { int fields; char server_version[VERSION_LENGTH+1]; - int server_status; server_version[0] = 0; @@ -1278,8 +1278,6 @@ try_again: * previous document. - FM */ { - char *cp; - if ((dump_output_immediately || traversal) && do_post && server_status != 303 && @@ -1298,36 +1296,8 @@ try_again: goto clean_up; } - /* - * Get the rest of the headers and data, if - * any, and then close the connection. - FM - */ - while ((status = HTTP_NETREAD(s, line_buffer, - (INIT_LINE_SIZE - 1), - handle)) > 0) { -#ifdef NOT_ASCII /* S/390 -- gil -- 0581 */ - { char *p; - - for ( p = line_buffer; p < line_buffer + status; p++ ) - *p = FROMASCII(*p); - } -#endif /* NOT_ASCII */ - line_buffer[status] = '\0'; - StrAllocCat(line_kept_clean, line_buffer); - } - HTTP_NETCLOSE(s, handle); - if (status == HT_INTERRUPTED) { - /* - * Impatient user. - FM - */ - CTRACE((tfp, "HTTP: Interrupted followup read.\n")); - _HTProgress (CONNECTION_INTERRUPTED); - status = HT_INTERRUPTED; - goto clean_up; - } - doing_redirect = TRUE; + HTProgress(line_buffer); if (server_status == 301) { /* Moved Permanently */ - HTProgress(line_buffer); if (do_post) { /* * Don't make the redirection permanent @@ -1340,341 +1310,8 @@ try_again: permanent_redirection = TRUE; } } + doing_redirect = TRUE; - /* - ** Look for "Set-Cookie:" and "Set-Cookie2:" headers. - FM - */ - if (LYSetCookies == TRUE) { - char *value = NULL; - char *SetCookie = NULL; - char *SetCookie2 = NULL; - cp = line_kept_clean; - while (*cp) { - /* - ** Assume a CRLF pair terminates - ** the header section. - FM - */ - if (*cp == CR) { - if (*(cp+1) == LF && - *(cp+2) == CR && *(cp+3) == LF) { - break; - } - } - if (TOUPPER(*cp) != 'S') { - cp++; - } else if (!strncasecomp(cp, "Set-Cookie:", 11)) { - char *cp1 = NULL, *cp2 = NULL; - cp += 11; -Cookie_continuation: - /* - * Trim leading spaces. - FM - */ - while (isspace((unsigned char)*cp)) - cp++; - /* - ** Accept CRLF, LF, or CR as end of line. - FM - */ - if (((cp1 = strchr(cp, LF)) != NULL) || - (cp2 = strchr(cp, CR)) != NULL) { - if (*cp1) { - *cp1 = '\0'; - if ((cp2 = strchr(cp, CR)) != NULL) - *cp2 = '\0'; - } else { - *cp2 = '\0'; - } - } - if (*cp == '\0') { - if (cp1) - *cp1 = LF; - if (cp2) - *cp2 = CR; - if (value != NULL) { - HTMIME_TrimDoubleQuotes(value); - if (SetCookie == NULL) { - StrAllocCopy(SetCookie, value); - } else { - StrAllocCat(SetCookie, ", "); - StrAllocCat(SetCookie, value); - } - FREE(value); - } - break; - } - StrAllocCat(value, cp); - cp += strlen(cp); - if (cp1) { - *cp1 = LF; - cp1 = NULL; - } - if (cp2) { - *cp2 = CR; - cp2 = NULL; - } - cp1 = cp; - if (*cp1 == CR) - cp1++; - if (*cp1 == LF) - cp1++; - if (*cp1 == ' ' || *cp1 == '\t') { - StrAllocCat(value, " "); - cp = cp1; - cp++; - cp1 = NULL; - goto Cookie_continuation; - } - HTMIME_TrimDoubleQuotes(value); - if (SetCookie == NULL) { - StrAllocCopy(SetCookie, value); - } else { - StrAllocCat(SetCookie, ", "); - StrAllocCat(SetCookie, value); - } - FREE(value); - } else if (!strncasecomp(cp, "Set-Cookie2:", 12)) { - char *cp1 = NULL, *cp2 = NULL; - cp += 12; -Cookie2_continuation: - /* - * Trim leading spaces. - FM - */ - while (isspace((unsigned char)*cp)) - cp++; - /* - ** Accept CRLF, LF, or CR as end of line. - FM - */ - if (((cp1 = strchr(cp, LF)) != NULL) || - (cp2 = strchr(cp, CR)) != NULL) { - if (*cp1) { - *cp1 = '\0'; - if ((cp2 = strchr(cp, CR)) != NULL) - *cp2 = '\0'; - } else { - *cp2 = '\0'; - } - } - if (*cp == '\0') { - if (cp1) - *cp1 = LF; - if (cp2) - *cp2 = CR; - if (value != NULL) { - HTMIME_TrimDoubleQuotes(value); - if (SetCookie2 == NULL) { - StrAllocCopy(SetCookie2, value); - } else { - StrAllocCat(SetCookie2, ", "); - StrAllocCat(SetCookie2, value); - } - FREE(value); - } - break; - } - StrAllocCat(value, cp); - cp += strlen(cp); - if (cp1) { - *cp1 = LF; - cp1 = NULL; - } - if (cp2) { - *cp2 = CR; - cp2 = NULL; - } - cp1 = cp; - if (*cp1 == CR) - cp1++; - if (*cp1 == LF) - cp1++; - if (*cp1 == ' ' || *cp1 == '\t') { - StrAllocCat(value, " "); - cp = cp1; - cp++; - cp1 = NULL; - goto Cookie2_continuation; - } - HTMIME_TrimDoubleQuotes(value); - if (SetCookie2 == NULL) { - StrAllocCopy(SetCookie2, value); - } else { - StrAllocCat(SetCookie2, ", "); - StrAllocCat(SetCookie2, value); - } - FREE(value); - } else { - cp++; - } - } - FREE(value); - if (SetCookie != NULL || SetCookie2 != NULL) { - LYSetCookie(SetCookie, SetCookie2, anAnchor->address); - FREE(SetCookie); - FREE(SetCookie2); - } - } - - /* - * Look for the "Location:" in the headers. - FM - */ - cp = line_kept_clean; - while (*cp) { - if (TOUPPER(*cp) != 'L') { - cp++; - } else if (!strncasecomp(cp, "Location:", 9)) { - char *cp1 = NULL, *cp2 = NULL; - cp += 9; - /* - * Trim leading spaces. - FM - */ - while (isspace((unsigned char)*cp)) - cp++; - /* - * Accept CRLF, LF, or CR as end of header. - FM - */ - if (((cp1 = strchr(cp, LF)) != NULL) || - (cp2 = strchr(cp, CR)) != NULL) { - if (*cp1) { - *cp1 = '\0'; - if ((cp2 = strchr(cp, CR)) != NULL) - *cp2 = '\0'; - } else { - *cp2 = '\0'; - } - /* - * Load the new URL into redirecting_url, - * and make sure it's not zero-length. - FM - */ - StrAllocCopy(redirecting_url, cp); - HTMIME_TrimDoubleQuotes(redirecting_url); - if (*redirecting_url == '\0') { - /* - * The "Location:" value is zero-length, and - * thus is probably something in the body, so - * we'll show the user what was returned. - FM - */ - CTRACE((tfp, "HTTP: 'Location:' is zero-length!\n")); - if (cp1) - *cp1 = LF; - if (cp2) - *cp2 = CR; - bad_location = TRUE; - FREE(redirecting_url); - HTAlert( - gettext("Got redirection with a bad Location header.")); - HTProgress(line_buffer); - break; - } - - /* - * Set up for checking redirecting_url in - * LYGetFile.c for restrictions before we - * seek the document at that Location. - FM - */ - HTProgress(line_buffer); - CTRACE((tfp, "HTTP: Picked up location '%s'\n", - redirecting_url)); - if (cp1) - *cp1 = LF; - if (cp2) - *cp2 = CR; - if (server_status == 305) { /* Use Proxy */ - /* - * Make sure the proxy field ends with - * a slash. - FM - */ - if (redirecting_url[strlen(redirecting_url)-1] - != '/') - StrAllocCat(redirecting_url, "/"); - /* - * Append our URL. - FM - */ - StrAllocCat(redirecting_url, anAnchor->address); - CTRACE((tfp, "HTTP: Proxy URL is '%s'\n", - redirecting_url)); - } - if (!do_post || - server_status == 303 || - server_status == 302) { - /* - * We don't have POST content (nor support PUT - * or DELETE), or the status is "See Other" or - * "General Redirection" and we can convert to - * GET, so go back and check out the new URL. - FM - */ - status = HT_REDIRECTING; - goto clean_up; - } - /* - * Make sure the user wants to redirect - * the POST content, or treat as GET - FM & DK - */ - switch (HTConfirmPostRedirect(redirecting_url, - server_status)) { - /* - * User failed to confirm. - * Abort the fetch. - */ - case 0: - doing_redirect = FALSE; - FREE(redirecting_url); - status = HT_NO_DATA; - goto clean_up; - - /* - * User wants to treat as GET with no content. - * Go back to check out the URL. - */ - case 303: - status = HT_REDIRECTING; - goto clean_up; - - /* - * Set the flag to retain the POST - * content and go back to check out - * the URL. - FM - */ - default: - status = HT_REDIRECTING; - redirect_post_content = TRUE; - goto clean_up; - } - } - break; - } else { - /* - * Keep looking for the Location header. - FM - */ - cp++; - } - } - - /* - * If we get to here, we didn't find the Location - * header, so we'll show the user what we got, if - * anything. - FM - */ - CTRACE((tfp, "HTTP: Failed to pick up location.\n")); - doing_redirect = FALSE; - permanent_redirection = FALSE; - start_of_data = line_kept_clean; - length = rawlength; - if (!bad_location) { - HTAlert(gettext("Got redirection with no Location header.")); - HTProgress(line_buffer); - } - if (traversal) { - HTTP_NETCLOSE(s, handle); - status = -1; - goto clean_up; - } - if (!dump_output_immediately && - format_out == HTAtom_for("www/download")) { - /* - * Convert a download request to - * a presentation request for - * interactive users. - FM - */ - format_out = WWW_PRESENT; - } break; } @@ -1901,6 +1538,13 @@ Cookie2_continuation: */ if (HTCheckForInterrupt()) { HTTP_NETCLOSE(s, handle); + if (doing_redirect) { + /* + * Impatient user. - FM + */ + CTRACE((tfp, "HTTP: Interrupted followup read.\n")); + _HTProgress (CONNECTION_INTERRUPTED); + } status = HT_INTERRUPTED; goto clean_up; } @@ -1919,6 +1563,24 @@ Cookie2_continuation: length = rawlength; #endif format_in = HTAtom_for("text/plain"); + + } else if (doing_redirect) { + + format_in = HTAtom_for("message/x-http-redirection"); + StrAllocCopy(anAnchor->content_type, HTAtom_name(format_in)); + if (traversal) { + format_out = WWW_DEBUG; + if (!sink) + sink = HTErrorStream(); + } else if (!dump_output_immediately && + format_out == HTAtom_for("www/download")) { + /* + * Convert a download request to + * a presentation request for + * interactive users. - FM + */ + format_out = WWW_PRESENT; + } } target = HTStreamStack(format_in, @@ -1946,12 +1608,23 @@ Cookie2_continuation: */ rv = HTCopy(anAnchor, s, (void *)handle, target); + /* + ** If we get here with doing_redirect set, it means that we were + ** looking for a Location header. We either have got it now in + ** redirecting_url - in that case the stream should not have loaded + ** any data. Or we didn't get it, in that case the stream may have + ** presented the message body normally. - kw + */ + if (rv == -1) { /* ** Intentional interrupt before data were received, not an error */ /* (*target->isa->_abort)(target, NULL); */ /* already done in HTCopy */ - status = HT_INTERRUPTED; + if (doing_redirect && traversal) + status = -1; + else + status = HT_INTERRUPTED; HTTP_NETCLOSE(s, handle); goto clean_up; } @@ -1961,21 +1634,29 @@ Cookie2_continuation: ** Aw hell, a REAL error, maybe cuz it's a dumb HTTP0 server */ (*target->isa->_abort)(target, NULL); - HTTP_NETCLOSE(s, handle); - if (!already_retrying && !do_post) { - CTRACE((tfp, "HTTP: Trying again with HTTP0 request.\n")); + if (doing_redirect && redirecting_url) { /* - ** May as well consider it an interrupt -- right? + ** Got a location before the error occurred? Then consider it + ** an interrupt but proceed below as normal. - kw */ - FREE(line_buffer); - FREE(line_kept_clean); - extensions = NO; - already_retrying = TRUE; - _HTProgress (RETRYING_AS_HTTP0); - goto try_again; + /* do nothing here */ } else { - status = HT_NOT_LOADED; - goto clean_up; + HTTP_NETCLOSE(s, handle); + if (!doing_redirect && !already_retrying && !do_post) { + CTRACE((tfp, "HTTP: Trying again with HTTP0 request.\n")); + /* + ** May as well consider it an interrupt -- right? + */ + FREE(line_buffer); + FREE(line_kept_clean); + extensions = NO; + already_retrying = TRUE; + _HTProgress (RETRYING_AS_HTTP0); + goto try_again; + } else { + status = HT_NOT_LOADED; + goto clean_up; + } } } @@ -1983,23 +1664,107 @@ Cookie2_continuation: ** Free if complete transmission (socket was closed before return). ** Close socket if partial transmission (was freed on abort). */ - if (rv != HT_INTERRUPTED) { + if (rv != HT_INTERRUPTED && rv != -2) { (*target->isa->_free)(target); } else { HTTP_NETCLOSE(s, handle); } if (doing_redirect) { - /* - ** We already jumped over all this if the "case 3:" code worked - ** above, but we'll check here as a backup in case it fails. - FM - */ - /* Lou's old comment: - FM */ - /* 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; + if (redirecting_url) { + /* + * Set up for checking redirecting_url in + * LYGetFile.c for restrictions before we + * seek the document at that Location. - FM + */ + CTRACE((tfp, "HTTP: Picked up location '%s'\n", + redirecting_url)); + if (rv == HT_INTERRUPTED) { + /* + ** Intentional interrupt after data were received, not an + ** error (probably). We take it as a user request to + ** abandon the redirection chain. + ** This could reasonably be changed (by just removing this + ** block), it would make sense if there are redirecting + ** resources that "hang" after sending the headers. - kw + */ + FREE(redirecting_url); + CTRACE((tfp, "HTTP: Interrupted followup read.\n")); + status = HT_INTERRUPTED; + goto clean_up; + } + HTProgress(line_buffer); + if (server_status == 305) { /* Use Proxy */ + /* + * Make sure the proxy field ends with + * a slash. - FM + */ + if (redirecting_url[strlen(redirecting_url)-1] + != '/') + StrAllocCat(redirecting_url, "/"); + /* + * Append our URL. - FM + */ + StrAllocCat(redirecting_url, anAnchor->address); + CTRACE((tfp, "HTTP: Proxy URL is '%s'\n", + redirecting_url)); + } + if (!do_post || + server_status == 303 || + server_status == 302) { + /* + * We don't have POST content (nor support PUT + * or DELETE), or the status is "See Other" or + * "General Redirection" and we can convert to + * GET, so go back and check out the new URL. - FM + */ + status = HT_REDIRECTING; + goto clean_up; + } + /* + * Make sure the user wants to redirect + * the POST content, or treat as GET - FM & DK + */ + switch (HTConfirmPostRedirect(redirecting_url, + server_status)) { + /* + * User failed to confirm. + * Abort the fetch. + */ + case 0: + doing_redirect = FALSE; + FREE(redirecting_url); + status = HT_NO_DATA; + goto clean_up; + + /* + * User wants to treat as GET with no content. + * Go back to check out the URL. + */ + case 303: + break; + + /* + * Set the flag to retain the POST + * content and go back to check out + * the URL. - FM + */ + default: + redirect_post_content = TRUE; + } + + /* Lou's old comment: - FM */ + /* 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 = traversal ? -1 : HT_LOADED; + } + } else { /* ** If any data were received, treat as a complete transmission diff --git a/WWW/Library/Implementation/HTUtils.h b/WWW/Library/Implementation/HTUtils.h index f977a9d5..686d784c 100644 --- a/WWW/Library/Implementation/HTUtils.h +++ b/WWW/Library/Implementation/HTUtils.h @@ -22,6 +22,7 @@ #ifdef DJGPP #include <sys/config.h> /* pseudo-autoconf values for DJGPP libc/headers */ #define HAVE_TRUNCATE 1 +#include <limits.h> #endif /* DJGPP */ #include <stdio.h> diff --git a/WWW/Library/djgpp/makefile b/WWW/Library/djgpp/makefile index ec874bfc..d5c46331 100644 --- a/WWW/Library/djgpp/makefile +++ b/WWW/Library/djgpp/makefile @@ -7,8 +7,16 @@ WWW_MACH = djgpp # The ASIS repository's name for the machine we are on #ASIS_MACH = hardware/os +# Use this option to enable optional and *experimental* color style. +#ENABLE_COLOR_STYLE = \ + -DUSE_COLOR_STYLE \ + -DUSE_HASH \ + -DLINKEDSTYLES + + CFLAGS = -O2 -DUSE_ZLIB -DDOSPATH -DNOUSERS -DDISP_PARTIAL \ -DDIRED_SUPPORT -DSOURCE_CACHE -DUSE_PSRC \ + $(ENABLE_COLOR_STYLE) \ -DEXP_FILE_UPLOAD \ -DWATT32 \ -I../Implementation \ |