diff options
Diffstat (limited to 'WWW/Library')
-rw-r--r-- | WWW/Library/Implementation/HTAlert.h | 4 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTAnchor.c | 22 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTAnchor.h | 16 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTFile.c | 237 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTFormat.c | 165 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTFormat.h | 20 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTMIME.c | 23 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTML.h | 4 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTNews.c | 373 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTStyle.h | 2 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTTCP.c | 107 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTTP.c | 139 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTUtils.h | 2 | ||||
-rw-r--r-- | WWW/Library/djgpp/makefile | 2 |
14 files changed, 982 insertions, 134 deletions
diff --git a/WWW/Library/Implementation/HTAlert.h b/WWW/Library/Implementation/HTAlert.h index ec1d2397..33d31f11 100644 --- a/WWW/Library/Implementation/HTAlert.h +++ b/WWW/Library/Implementation/HTAlert.h @@ -112,6 +112,7 @@ extern BOOL HTConfirmCookie PARAMS(( ** ---------------------------- ** On entry, ** redirecting_url is the Location. +** server_status is the server status code. ** ** On exit, ** Returns 0 on cancel, @@ -119,7 +120,8 @@ extern BOOL HTConfirmCookie PARAMS(( ** 303 for redirect as GET without content */ extern int HTConfirmPostRedirect PARAMS(( - CONST char * redirecting_url)); + CONST char * redirecting_url, + int server_status)); /* diff --git a/WWW/Library/Implementation/HTAnchor.c b/WWW/Library/Implementation/HTAnchor.c index 49ef2090..397c3684 100644 --- a/WWW/Library/Implementation/HTAnchor.c +++ b/WWW/Library/Implementation/HTAnchor.c @@ -949,8 +949,8 @@ PUBLIC void HTAnchor_setRevTitle ARGS2( } /* Suggested filename handling. - FM -** (will be loaded if we had a Content-disposition -** header with file; filename=name.suffix) +** (will be loaded if we had a Content-Disposition +** header or META element with filename=name.suffix) */ PUBLIC CONST char * HTAnchor_SugFname ARGS1( HTParentAnchor *, me) @@ -958,6 +958,24 @@ PUBLIC CONST char * HTAnchor_SugFname ARGS1( return me ? me->SugFname : NULL; } +/* Content-Encoding handling. - FM +** (will be loaded if we had a Content-Encoding +** header.) +*/ +PUBLIC CONST char * HTAnchor_content_encoding ARGS1( + HTParentAnchor *, me) +{ + return me ? me->content_encoding : NULL; +} + +/* Content-Type handling. - FM +*/ +PUBLIC CONST char * HTAnchor_content_type ARGS1( + HTParentAnchor *, me) +{ + return me ? me->content_type : NULL; +} + /* Last-Modified header handling. - FM */ PUBLIC CONST char * HTAnchor_last_modified ARGS1( diff --git a/WWW/Library/Implementation/HTAnchor.h b/WWW/Library/Implementation/HTAnchor.h index 052290cf..8818b36d 100644 --- a/WWW/Library/Implementation/HTAnchor.h +++ b/WWW/Library/Implementation/HTAnchor.h @@ -313,12 +313,24 @@ extern void HTAnchor_setRevTitle PARAMS(( CONST char * title)); /* Suggested filename handling. - FM -** (will be loaded if we had a Content-disposition -** header with file; filename=name.suffix) +** (will be loaded if we had a Content-Disposition +** header or META element with filename=name.suffix) */ extern CONST char * HTAnchor_SugFname PARAMS(( HTParentAnchor * me)); +/* Content-Type handling. - FM +*/ +extern CONST char * HTAnchor_content_type PARAMS(( + HTParentAnchor * me)); + +/* Content-Encoding handling. - FM +** (will be loaded if we had a Content-Encoding +** header.) +*/ +extern CONST char * HTAnchor_content_encoding PARAMS(( + HTParentAnchor * me)); + /* Last-Modified header handling. - FM */ extern CONST char * HTAnchor_last_modified PARAMS(( diff --git a/WWW/Library/Implementation/HTFile.c b/WWW/Library/Implementation/HTFile.c index 99f0cc41..53f082ab 100644 --- a/WWW/Library/Implementation/HTFile.c +++ b/WWW/Library/Implementation/HTFile.c @@ -705,7 +705,8 @@ PUBLIC HTFormat HTFileFormat ARGS2( if (!HTSuffixes) HTFileInit(); #endif /* !NO_INIT */ - *pencoding = NULL; + if (pencoding) + *pencoding = NULL; lf = strlen(filename); n = HTList_count(HTSuffixes); for (i = 0; i < n; i++) { @@ -714,7 +715,8 @@ PUBLIC HTFormat HTFileFormat ARGS2( ls = strlen(suff->suffix); if ((ls <= lf) && 0 == strcasecomp(suff->suffix, filename + lf - ls)) { int j; - *pencoding = suff->encoding; + if (pencoding) + *pencoding = suff->encoding; if (suff->rep) { #ifdef VMS if (semicolon != NULL) @@ -750,7 +752,7 @@ PUBLIC HTFormat HTFileFormat ARGS2( /* ** Set default encoding unless found with suffix already. */ - if (!*pencoding) + if (pencoding && !*pencoding) *pencoding = suff->encoding ? suff->encoding : HTAtom_for("binary"); #ifdef VMS @@ -772,7 +774,6 @@ PUBLIC HTFormat HTCharsetFormat ARGS3( HTFormat, format, HTParentAnchor *, anchor, int, default_LYhndl) - { char *cp = NULL, *cp1, *cp2, *cp3 = NULL, *cp4; BOOL chartrans_ok = FALSE; @@ -794,9 +795,9 @@ PUBLIC HTFormat HTCharsetFormat ARGS3( cp2++; #ifdef EXP_CHARTRANS StrAllocCopy(cp3, cp2); /* copy to mutilate more */ - for (cp4=cp3; (*cp4 != '\0' && *cp4 != '"' && - *cp4 != ';' && *cp4 != ':' && - !WHITE(*cp4)); cp4++) { + for (cp4 = cp3; (*cp4 != '\0' && *cp4 != '"' && + *cp4 != ';' && *cp4 != ':' && + !WHITE(*cp4)); cp4++) { ; /* do nothing */ } *cp4 = '\0'; @@ -813,29 +814,29 @@ PUBLIC HTFormat HTCharsetFormat ARGS3( } } if (UCCanTranslateFromTo(chndl, current_char_set)) { - chartrans_ok = YES; - *cp1 = '\0'; - format = HTAtom_for(cp); - StrAllocCopy(anchor->charset, cp4); - HTAnchor_setUCInfoStage(anchor, chndl, - UCT_STAGE_MIME, UCT_SETBY_MIME); + chartrans_ok = YES; + *cp1 = '\0'; + format = HTAtom_for(cp); + StrAllocCopy(anchor->charset, cp4); + HTAnchor_setUCInfoStage(anchor, chndl, + UCT_STAGE_MIME, UCT_SETBY_MIME); } else if (chndl < 0) { /* ** Got something but we don't recognize it. */ - chndl = UCLYhndl_for_unrec; + chndl = UCLYhndl_for_unrec; if (UCCanTranslateFromTo(chndl, current_char_set)) { - chartrans_ok = YES; - HTAnchor_setUCInfoStage(anchor, chndl, - UCT_STAGE_MIME, UCT_SETBY_DEFAULT); - } - } - FREE(cp3); - if (chartrans_ok) { + chartrans_ok = YES; + HTAnchor_setUCInfoStage(anchor, chndl, + UCT_STAGE_MIME, UCT_SETBY_DEFAULT); + } + } + FREE(cp3); + if (chartrans_ok) { LYUCcharset *p_in = HTAnchor_getUCInfoStage(anchor, - UCT_STAGE_MIME); + UCT_STAGE_MIME); LYUCcharset *p_out = HTAnchor_setUCInfoStage(anchor, - current_char_set, + current_char_set, UCT_STAGE_HTEXT, UCT_SETBY_DEFAULT); if (!p_out) { @@ -861,7 +862,7 @@ PUBLIC HTFormat HTCharsetFormat ARGS3( UCT_SETBY_DEFAULT); } if (!(p_in->enc & UCT_ENC_CJK) && - (p_in->codepoints & UCT_CP_SUBSETOF_LAT1)){ + (p_in->codepoints & UCT_CP_SUBSETOF_LAT1)) { HTCJK = NOCJK; } else if (chndl == current_char_set) { HTPassEightBitRaw = TRUE; @@ -1421,6 +1422,10 @@ PUBLIC int HTLoadFile ARGS4( #else extern char *list_format; #endif /* VMS */ +#ifdef USE_ZLIB + gzFile gzfp; + BOOL use_gzread = NO; +#endif /* USE_ZLIB */ /* ** Reduce the filename to a basic form (hopefully unique!). @@ -1436,11 +1441,11 @@ PUBLIC int HTLoadFile ARGS4( if (strcmp("ftp", access) == 0 || (strcmp("localhost", nodename) != 0 && #ifdef VMS - strcasecomp(nodename, HTHostName()) != 0)) + strcasecomp(nodename, HTHostName()) != 0 #else - strcmp(nodename, HTHostName()) != 0)) + strcmp(nodename, HTHostName()) != 0 #endif /* VMS */ - { + )) { FREE(newname); FREE(filename); FREE(nodename); @@ -1540,7 +1545,6 @@ PUBLIC int HTLoadFile ARGS4( int len; char *cp = NULL; char *semicolon = NULL; - int status; if (HTEditable(vmsname)) { HTAtom * put = HTAtom_for("PUT"); @@ -1588,7 +1592,20 @@ PUBLIC int HTLoadFile ARGS4( UCLYhndl_HTFile_for_unspec); StrAllocCopy(anchor->content_type, format->name); StrAllocCopy(anchor->content_encoding, "x-gzip"); +#ifdef USE_ZLIB + if (strcmp(format_out->name, "www/download") != 0) { + fclose(fp); + gzfp = gzopen(localname, "rb"); + + if (TRACE) + fprintf(stderr, + "HTLoadFile: gzopen of `%s' gives %p\n", + localname, (void*)gzfp); + use_gzread = YES; + } +#else /* USE_ZLIB */ format = HTAtom_for("www/compressed"); +#endif /* USE_ZLIB */ } } } @@ -1596,8 +1613,43 @@ PUBLIC int HTLoadFile ARGS4( *semicolon = ';'; FREE(filename); FREE(nodename); - status = HTParseFile(format, format_out, anchor, fp, sink); - fclose(fp); +#ifdef USE_ZLIB + if (use_gzread) { + if (gzfp) { + char * sugfname = NULL; + if (anchor->SugFname) { + StrAllocCopy(sugfname, anchor->SugFname); + } else { + char * anchor_path = HTParse(anchor->address, "", + PARSE_PATH + PARSE_PUNCTUATION); + char * lastslash; + HTUnEscape(anchor_path); + lastslash = strrchr(anchor_path, '/'); + if (lastslash) + StrAllocCopy(sugfname, lastslash + 1); + FREE(anchor_path); + } + FREE(anchor->content_encoding); + if (sugfname && *sugfname) + HTCheckFnameForCompression(&sugfname, anchor, + TRUE); + if (sugfname && *sugfname) + StrAllocCopy(anchor->SugFname, sugfname); + FREE(sugfname); + status = HTParseGzFile(format, format_out, + anchor, + gzfp, sink); + } else { + status = HTLoadError(NULL, + -(HT_ERROR), + "Could not open file for decompression!"); + } + } else +#endif /* USE_GZREAD */ + { + status = HTParseFile(format, format_out, anchor, fp, sink); + fclose(fp); + } return status; } /* If successfull open */ FREE(filename); @@ -1635,7 +1687,7 @@ PUBLIC int HTLoadFile ARGS4( STRUCT_DIRENT * dirbuf; float best = NO_VALUE_FOUND; /* So far best is bad */ HTFormat best_rep = NULL; /* Set when rep found */ - STRUCT_DIRENT best_dirbuf; /* Best dir entry so far */ + char * best_name = NULL; /* Best dir entry so far */ char *base = strrchr(localname, '/'); int baselen; @@ -1665,10 +1717,55 @@ forget_multi: #endif if ((int)strlen(dirbuf->d_name) > baselen && /* Match? */ !strncmp(dirbuf->d_name, base, baselen)) { - HTFormat rep = HTFileFormat(dirbuf->d_name, &encoding); + HTFormat rep = HTFileFormat(dirbuf->d_name, NULL); + float filevalue = HTFileValue(dirbuf->d_name); float value = HTStackValue(rep, format_out, - HTFileValue(dirbuf->d_name), - 0.0 /* @@@@@@ */); + filevalue, + 0L /* @@@@@@ */); + if (value <= 0.0) { + char * cp = NULL; + int len = strlen(dirbuf->d_name); + if (len > 2 && + dirbuf->d_name[len - 1] == 'Z' && + dirbuf->d_name[len - 2] == '.') { + StrAllocCopy(cp, dirbuf->d_name); + cp[len - 2] = '\0'; + format = HTFileFormat(cp, NULL); + FREE(cp); + value = HTStackValue(format, format_out, + filevalue, 0); + if (value <= 0.0) { + format = HTAtom_for("application/x-compressed"); + value = HTStackValue(format, format_out, + filevalue, 0); + } + if (value <= 0.0) { + format = HTAtom_for("www/compressed"); + value = HTStackValue(format, format_out, + filevalue, 0); + } + } else if ((len > 3) && + !strcasecomp((char *)&dirbuf->d_name[len - 2], + "gz") && + dirbuf->d_name[len - 3] == '.') { + StrAllocCopy(cp, dirbuf->d_name); + cp[len - 3] = '\0'; + format = HTFileFormat(cp, NULL); + FREE(cp); + value = HTStackValue(format, format_out, + filevalue, 0); + if (value <= 0.0) { + format = HTAtom_for("application/x-gzip"); + value = HTStackValue(format, format_out, + filevalue, 0); + } + if (value <= 0.0) { + format = HTAtom_for("www/compressed"); + value = HTStackValue(format, format_out, + filevalue, 0); + } + } + } if (value != NO_VALUE_FOUND) { if (TRACE) fprintf(stderr, @@ -1677,7 +1774,7 @@ forget_multi: if (value > best) { best_rep = rep; best = value; - best_dirbuf = *dirbuf; + StrAllocCopy(best_name, dirbuf->d_name); } } /* if best so far */ } /* if match */ @@ -1689,8 +1786,9 @@ forget_multi: format = best_rep; base[-1] = '/'; /* Restore directory name */ base[0] = '\0'; - StrAllocCat(localname, best_dirbuf.d_name); - goto open_file; + StrAllocCat(localname, best_name); + FREE(best_name); + /* goto open_file; */ /* Nope - might be a directory - kw */ } else { /* If not found suitable file */ FREE(localname); @@ -1711,10 +1809,11 @@ forget_multi: ** to point to the current directory being read. */ #ifdef _WINDOWS - if (!exists(localname)) { + if (!exists(localname)) #else - if (stat(localname,&dir_info) == -1) { /* get file information */ + if (stat(localname,&dir_info) == -1) /* get file information */ #endif + { /* if can't read file information */ if (TRACE) fprintf(stderr, "HTLoadFile: can't stat %s\n", localname); @@ -1966,6 +2065,11 @@ forget_multi: "Subirectories:" : "Files:"); END(HTML_EM); } + END(HTML_H2); +#ifndef LONG_LIST + START(HTML_DIR); +#endif /* !LONG_LIST */ + } #else if (state != *(char *)(HTBTree_object( next_element))) { @@ -1981,12 +2085,12 @@ forget_multi: PUTS(state == 'D' ? "Subdirectories:" : "Files:"); END(HTML_EM); -#endif /* DIRED_SUPPORT */ END(HTML_H2); #ifndef LONG_LIST START(HTML_DIR); #endif /* !LONG_LIST */ } +#endif /* DIRED_SUPPORT */ #ifndef LONG_LIST START(HTML_LI); #endif /* !LONG_LIST */ @@ -2053,7 +2157,6 @@ open_file: if (fp) { /* Good! */ int len; char *cp = NULL; - int status; if (HTEditable(localname)) { HTAtom * put = HTAtom_for("PUT"); @@ -2089,13 +2192,61 @@ open_file: UCLYhndl_HTFile_for_unspec); StrAllocCopy(anchor->content_type, format->name); StrAllocCopy(anchor->content_encoding, "x-gzip"); +#ifdef USE_ZLIB + if (strcmp(format_out->name, "www/download") != 0) { + fclose(fp); + gzfp = gzopen(localname, "rb"); + + if (TRACE) + fprintf(stderr, + "HTLoadFile: gzopen of `%s' gives %p\n", + localname, (void*)gzfp); + use_gzread = YES; + } +#else /* USE_ZLIB */ format = HTAtom_for("www/compressed"); +#endif /* USE_ZLIB */ } } FREE(localname); FREE(nodename); - status = HTParseFile(format, format_out, anchor, fp, sink); - fclose(fp); +#ifdef USE_ZLIB + if (use_gzread) { + if (gzfp) { + char * sugfname = NULL; + if (anchor->SugFname) { + StrAllocCopy(sugfname, anchor->SugFname); + } else { + char * anchor_path = HTParse(anchor->address, "", + PARSE_PATH + PARSE_PUNCTUATION); + char * lastslash; + HTUnEscape(anchor_path); + lastslash = strrchr(anchor_path, '/'); + if (lastslash) + StrAllocCopy(sugfname, lastslash + 1); + FREE(anchor_path); + } + FREE(anchor->content_encoding); + if (sugfname && *sugfname) + HTCheckFnameForCompression(&sugfname, anchor, + TRUE); + if (sugfname && *sugfname) + StrAllocCopy(anchor->SugFname, sugfname); + FREE(sugfname); + status = HTParseGzFile(format, format_out, + anchor, + gzfp, sink); + } else { + status = HTLoadError(NULL, + -(HT_ERROR), + "Could not open file for decompression!"); + } + } else +#endif /* USE_GZREAD */ + { + status = HTParseFile(format, format_out, anchor, fp, sink); + fclose(fp); + } return status; } /* If succesfull open */ } /* scope of fp */ diff --git a/WWW/Library/Implementation/HTFormat.c b/WWW/Library/Implementation/HTFormat.c index c8bda5de..b5f8584d 100644 --- a/WWW/Library/Implementation/HTFormat.c +++ b/WWW/Library/Implementation/HTFormat.c @@ -661,6 +661,99 @@ PUBLIC int HTFileCopy ARGS2( return rv; } +#ifdef USE_ZLIB +/* Push data from a gzip file pointer down a stream +** ------------------------------------- +** +** This routine is responsible for creating and PRESENTING any +** graphic (or other) objects described by the file. +** +** +*/ +PRIVATE int HTGzFileCopy ARGS2( + gzFile, gzfp, + HTStream*, sink) +{ + HTStreamClass targetClass; + char line[256]; + int status, bytes = 0, nreads = 0, nprogr = 0; + int gzerrnum; + int rv = HT_OK; + + /* Push the data down the stream + */ + targetClass = *(sink->isa); /* Copy pointers to procedures */ + + /* read and inflate gzipped file, and push binary down sink + */ + for (;;) { + status = gzread(gzfp, input_buffer, INPUT_BUFFER_SIZE); + nreads++; + if (status <= 0) { /* EOF or error */ + if (status == 0) { + rv = HT_LOADED; + break; + } + if (TRACE) { + fprintf(stderr, + "HTGzFileCopy: Read error, gzread returns %d\n", + status); + fprintf(stderr, + "gzerror : %s\n", + gzerror(gzfp, &gzerrnum)); + if (gzerrnum == Z_ERRNO) + perror("gzerror "); + } + if (bytes) { + rv = HT_PARTIAL_CONTENT; + } else { + rv = -1; + } + break; + } + (*targetClass.put_block)(sink, input_buffer, status); + + bytes += status; + if (nreads >= 100) { + /* + ** Show progress messages for local files, and check for + ** user interruption. Start doing so only after a certain + ** number of reads have been done, and don't update it on + ** every read (normally reading in a local file should be + ** speedy). - KW + */ + if (nprogr == 0) { + if (bytes < 1024000) { + sprintf(line, + "Read %d uncompressed bytes of data.", bytes); + } else { + sprintf(line, "Read %d uncompressed KB of data. %s", + bytes/1024, + "(Press 'z' to abort.)"); + } + HTProgress(line); + if (HTCheckForInterrupt()) { + _HTProgress ("Data transfer interrupted."); + if (bytes) { + rv = HT_INTERRUPTED; + } else { + rv = -1; + } + break; + } + nprogr++; + } else if (nprogr == 25) { + nprogr = 0; + } else { + nprogr++; + } + } + } /* next bufferload */ + + return rv; +} +#endif /* USE_ZLIB */ + /* Push data from a socket down a stream STRIPPING CR ** -------------------------------------------------- ** @@ -807,6 +900,78 @@ PUBLIC int HTParseFile ARGS5( return HT_LOADED; } +#ifdef USE_ZLIB +PRIVATE int HTCloseGzFile ARGS1( + gzFile, gzfp) +{ + int gzres; + if (gzfp == NULL) + return 0; + gzres = gzclose(gzfp); + if (TRACE) { + if (gzres == Z_ERRNO) { + perror("gzclose "); + } else if (gzres != Z_OK) { + fprintf(stderr, "gzclose : error number %d\n", gzres); + } + } + return(gzres); +} + +PUBLIC int HTParseGzFile ARGS5( + HTFormat, rep_in, + HTFormat, format_out, + HTParentAnchor *, anchor, + gzFile, gzfp, + HTStream*, sink) +{ + HTStream * stream; + HTStreamClass targetClass; + int rv; + + stream = HTStreamStack(rep_in, + format_out, + sink , anchor); + + if (!stream) { + char buffer[1024]; /* @@@@@@@@ */ + extern char LYCancelDownload; + HTCloseGzFile(gzfp); + if (LYCancelDownload) { + LYCancelDownload = FALSE; + return -1; + } + sprintf(buffer, "Sorry, can't convert from %s to %s.", + HTAtom_name(rep_in), HTAtom_name(format_out)); + if (TRACE) + fprintf(stderr, "HTFormat(in HTParseGzFile): %s\n", buffer); + return HTLoadError(sink, 501, buffer); + } + + /* 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 = HTGzFileCopy(gzfp, stream); + if (rv == -1 || rv == HT_INTERRUPTED) { + (*targetClass._abort)(stream, NULL); + } else { + (*targetClass._free)(stream); + } + + HTCloseGzFile(gzfp); + 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; +} +#endif /* USE_ZLIB */ + /* Converter stream: Network Telnet to internal character text ** ----------------------------------------------------------- ** diff --git a/WWW/Library/Implementation/HTFormat.h b/WWW/Library/Implementation/HTFormat.h index 24972f06..812e2fc3 100644 --- a/WWW/Library/Implementation/HTFormat.h +++ b/WWW/Library/Implementation/HTFormat.h @@ -359,6 +359,26 @@ extern int HTParseFile PARAMS(( FILE *fp, HTStream* sink)); +#ifdef USE_ZLIB + +#ifdef USE_ZLIB +#include <zlib.h> +#endif /* USE_ZLIB */ +/* +HTParseGzFile: Parse a gzipped File through a file pointer + + This routine is called by protocols modules to load an object. uses HTStreamStack and + HTGzFileCopy . Returns HT_LOADED if succesful, <0 if not. + */ +extern int HTParseGzFile PARAMS(( + HTFormat format_in, + HTFormat format_out, + HTParentAnchor *anchor, + gzFile gzfp, + HTStream* sink)); + +#endif /* USE_ZLIB */ + /* HTNetToText: Convert Net ASCII to local representation diff --git a/WWW/Library/Implementation/HTMIME.c b/WWW/Library/Implementation/HTMIME.c index 2b9e31e4..60645dee 100644 --- a/WWW/Library/Implementation/HTMIME.c +++ b/WWW/Library/Implementation/HTMIME.c @@ -972,7 +972,7 @@ PRIVATE void HTMIME_put_character ARGS2( } /* switch on character */ break; - case miS: /* Check for 'a; or 'e' */ + case miS: /* Check for 'a' or 'e' */ switch (c) { case 'a': case 'A': @@ -1565,25 +1565,24 @@ PRIVATE void HTMIME_put_character ARGS2( */ StrAllocCopy(me->anchor->content_disposition, me->value); /* - ** If it includes file; filename=name.suffix - ** load the me->SugFname element. - FM + ** 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, "file;", 5)) - cp++; - if (*cp == '\0') - break; - cp += 5; - while (*cp != '\0' && WHITE(*cp)) + while (*cp != '\0' && strncasecomp(cp, "filename", 8)) cp++; if (*cp == '\0') break; - while (*cp != '\0' && strncasecomp(cp, "filename", 8)) + cp += 8; + while ((*cp != '\0') && (WHITE(*cp) || *cp == '=')) cp++; if (*cp == '\0') break; - cp += 8; - while (*cp == ' ' || *cp == '=') + while (*cp != '\0' && WHITE(*cp)) cp++; if (*cp == '\0') break; diff --git a/WWW/Library/Implementation/HTML.h b/WWW/Library/Implementation/HTML.h index 2aaa8c0f..7480b678 100644 --- a/WWW/Library/Implementation/HTML.h +++ b/WWW/Library/Implementation/HTML.h @@ -88,8 +88,8 @@ struct _HTStructured { * Used for nested lists. - FM */ int List_Nesting_Level; /* counter for list nesting level */ - int OL_Counter[7]; /* counter for ordered lists */ - char OL_Type[7]; /* types for ordered lists */ + int OL_Counter[12]; /* counter for ordered lists */ + char OL_Type[12]; /* types for ordered lists */ int Last_OL_Count; /* last count in ordered lists */ char Last_OL_Type; /* last type in ordered lists */ diff --git a/WWW/Library/Implementation/HTNews.c b/WWW/Library/Implementation/HTNews.c index 21da80d8..bcf2993e 100644 --- a/WWW/Library/Implementation/HTNews.c +++ b/WWW/Library/Implementation/HTNews.c @@ -78,6 +78,7 @@ PRIVATE HTStructured * target; /* The output sink */ PRIVATE HTStructuredClass targetClass; /* Copy of fn addresses */ PRIVATE HTParentAnchor *node_anchor; /* Its anchor */ PRIVATE int diagnostic; /* level: 0=none 2=source */ +PRIVATE HTList *NNTP_AuthInfo = NULL; /* AUTHINFO database */ #define PUTC(c) (*targetClass.put_character)(target, c) #define PUTS(s) (*targetClass.put_string)(target, s) @@ -86,13 +87,42 @@ PRIVATE int diagnostic; /* level: 0=none 2=source */ #define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \ (*targetClass.end_element)(target, e, 0) +typedef struct _NNTPAuth { + char * host; + char * user; + char * pass; +} NNTPAuth; + PRIVATE void free_news_globals NOARGS { + if (s >= 0) { + NEWS_NETCLOSE(s); + s = -1; + } FREE(HTNewsHost); FREE(NewsHost); FREE(NewsHREF); } +PRIVATE void free_NNTP_AuthInfo NOARGS +{ + HTList *cur = NNTP_AuthInfo; + NNTPAuth *auth = NULL; + + if (!cur) + return; + + while (NULL != (auth = (NNTPAuth *)HTList_nextObject(cur))) { + FREE(auth->host); + FREE(auth->user); + FREE(auth->pass); + FREE(auth); + } + HTList_delete(NNTP_AuthInfo); + NNTP_AuthInfo = NULL; + return; +} + PUBLIC CONST char * HTGetNewsHost NOARGS { return HTNewsHost; @@ -260,6 +290,239 @@ PRIVATE BOOL match ARGS2 (CONST char *,unknown, CONST char *,template) return (BOOL)(*t == 0); /* OK if end of template */ } +typedef enum { + NNTPAUTH_ERROR = 0, /* general failure */ + NNTPAUTH_OK = 281, /* authenticated successfully */ + NNTPAUTH_CLOSE = 502 /* server probably closed connection */ +} NNTPAuthResult; +/* +** This function handles nntp authentication. - FM +*/ +PRIVATE NNTPAuthResult HTHandleAuthInfo ARGS1( + char *, host) +{ + HTList *cur = NULL; + NNTPAuth *auth = NULL; + char *UserName = NULL; + char *PassWord = NULL; + char *msg = NULL; + char buffer[512]; + int status, tries; + extern BOOL dump_output_immediately; + + /* + ** Make sure we have an interactive user and a host. - FM + */ + if (dump_output_immediately || !(host && *host)) + return NNTPAUTH_ERROR; + + /* + ** Check for an existing authorization entry. - FM + */ + if (NNTP_AuthInfo != NULL) { + cur = NNTP_AuthInfo; + while (NULL != (auth = (NNTPAuth *)HTList_nextObject(cur))) { + if (!strcmp(auth->host, host)) { + UserName = auth->user; + PassWord = auth->pass; + break; + } + } + } else { + NNTP_AuthInfo = HTList_new(); + atexit(free_NNTP_AuthInfo); + } + + /* + ** Handle the username. - FM + */ + buffer[511] = '\0'; + tries = 3; + + while (tries) { + if (UserName == NULL) { + if ((msg = (char *)calloc(1, (strlen(host) + 30))) == NULL) { + outofmem(__FILE__, "HTHandleAuthInfo"); + } + sprintf(msg, "Username for news host '%s':", host); + UserName = HTPrompt(msg, NULL); + FREE(msg); + if (!(UserName && *UserName)) { + FREE(UserName); + return NNTPAUTH_ERROR; + } + } + sprintf(buffer, "AUTHINFO USER %.*s%c%c", 495, UserName, CR, LF); + if ((status = response(buffer)) < 0) { + if (status == HT_INTERRUPTED) + _HTProgress("Connection interrupted."); + else + HTAlert("Connection closed ???"); + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + auth->user = UserName; + } + } else { + FREE(UserName); + } + return NNTPAUTH_CLOSE; + } + if (status == 281) { + /* + ** Username is OK and no Password is required. - FM + */ + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + auth->user = UserName; + } + } else { + if ((auth = + (NNTPAuth *)calloc(1, sizeof(NNTPAuth))) != NULL) { + StrAllocCopy(auth->host, host); + auth->user = UserName; + HTList_appendObject(NNTP_AuthInfo, auth); + } + } + return NNTPAUTH_OK; + } + if (status != 381) { + /* + ** Not a request for the password, so it must be an error. - FM + */ + HTAlert(response_text); + tries--; + if ((tries > 0) && HTConfirm("Change username?")) { + if (!auth || auth->user != UserName) { + FREE(UserName); + } + if ((UserName = HTPrompt("Username:", UserName)) != NULL && + *UserName) { + continue; + } + } + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + } + FREE(auth->pass); + } + FREE(UserName); + return NNTPAUTH_ERROR; + } + break; + } + + if (status == 381) { + /* + ** Username is OK, and a password is required. - FM + */ + tries = 3; + while (tries) { + if (PassWord == NULL) { + if ((msg = (char *)calloc(1, (strlen(host) + 30))) == NULL) { + outofmem(__FILE__, "HTHandleAuthInfo"); + } + sprintf(msg, "Password for news host '%s':", host); + PassWord = HTPromptPassword(msg); + FREE(msg); + if (!(PassWord && *PassWord)) { + FREE(PassWord); + return NNTPAUTH_ERROR; + } + } + sprintf(buffer, "AUTHINFO PASS %.*s%c%c", 495, PassWord, CR, LF); + if ((status = response(buffer)) < 0) { + if (status == HT_INTERRUPTED) { + _HTProgress("Connection interrupted."); + } else { + HTAlert("Connection closed ???"); + } + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + auth->user = UserName; + } + if (auth->pass != PassWord) { + FREE(auth->pass); + auth->pass = PassWord; + } + } else { + FREE(UserName); + FREE(PassWord); + } + return NNTPAUTH_CLOSE; + } + if (status == 502) { + /* + * That's what INN's nnrpd returns. + * It closes the connection after this. - kw + */ + HTAlert(response_text); + if (auth) { + if (auth->user == UserName) + UserName = NULL; + FREE(auth->user); + if (auth->pass == PassWord) + PassWord = NULL; + FREE(auth->pass); + } + FREE(UserName); + FREE(PassWord); + return NNTPAUTH_CLOSE; + } + if (status == 281) { + /* + ** Password is OK. - FM + */ + if (auth) { + if (auth->user != UserName) { + FREE(auth->user); + auth->user = UserName; + } + if (auth->pass != PassWord) { + FREE(auth->pass); + auth->pass = PassWord; + } + } else { + if ((auth = + (NNTPAuth *)calloc(1, sizeof(NNTPAuth))) != NULL) { + StrAllocCopy(auth->host, host); + auth->user = UserName; + auth->pass = PassWord; + HTList_appendObject(NNTP_AuthInfo, auth); + } + } + return NNTPAUTH_OK; + } + /* + ** Show the error message and see if we should try again. - FM + */ + HTAlert(response_text); + if (!auth || auth->pass != PassWord) { + FREE(PassWord); + } else { + PassWord = NULL; + } + tries--; + if ((tries > 0) && HTConfirm("Change password?")) { + continue; + } + if (auth) { + if (auth->user == UserName) + UserName = NULL; + FREE(auth->user); + FREE(auth->pass); + } + FREE(UserName); + break; + } + } + + return NNTPAUTH_ERROR; +} + /* Find Author's name in mail address ** ---------------------------------- ** @@ -1919,7 +2182,7 @@ PUBLIC int HTLoadNews ARGS4( if (post_wanted || reply_wanted || spost_wanted || sreply_wanted) { strcpy(command, "POST"); } else if (list_wanted) { - strcpy(command, "LIST NEWSGROUPS"); + sprintf(command, "XGTITLE %.*s", 249, p1); } else if (group_wanted) { char * slash = strchr(p1, '/'); strcpy(command, "GROUP "); @@ -2170,10 +2433,10 @@ PUBLIC int HTLoadNews ARGS4( } else { /* ** Ensure reader mode, but don't bother checking the - ** status for anything but HT_INERRUPTED, because if - ** the reader mode command is not needed, the server - ** probably return a 500, which is irrelevant at - ** this point. - FM + ** status for anything but HT_INTERRUPTED or a 480 + ** Authorization request, because if the reader mode + ** command is not needed, the server probably returned + ** a 500, which is irrelevant at this point. - FM */ char buffer[20]; @@ -2182,6 +2445,22 @@ PUBLIC int HTLoadNews ARGS4( _HTProgress("Connection interrupted."); break; } + if (status == 480) { + NNTPAuthResult auth_result = HTHandleAuthInfo(NewsHost); + if (auth_result == NNTPAUTH_CLOSE) { + if (s != -1 && !(ProxyHost || ProxyHREF)) { + NEWS_NETCLOSE(s); + s = -1; + } + } + if (auth_result != NNTPAUTH_OK) { + break; + } + if ((status = response(buffer)) == HT_INTERRUPTED) { + _HTProgress("Connection interrupted."); + break; + } + } } Send_NNTP_command: @@ -2196,12 +2475,41 @@ Send_NNTP_command: break; } } + /* + * For some well known error responses which are expected + * to occur in normal use, break from the loop without retrying + * and without closing the connection. It is unlikely that + * these are leftovers from a timed-out connection (but we do + * some checks to see whether the response rorresponds to the + * last command), or that they will give anything else when + * automatically retried. - kw + */ + if (status == 411 && group_wanted && + !strncmp(command, "GROUP ", 6) && + !strncasecomp(response_text + 3, " No such group ", 15) && + !strcmp(response_text + 18, groupName)) { + + HTAlert(response_text); + break; + } else if (status == 430 && !group_wanted && !list_wanted && + !strncmp(command, "ARTICLE <", 9) && + !strcasecomp(response_text + 3, " No such article")) { + + HTAlert(response_text); + break; + } if ((status/100) != 2 && - status != 340) { - if (retries) + status != 340 && + status != 480) { + if (retries) { + if (list_wanted && !strncmp(command, "XGTITLE", 7)) { + sprintf(command, "LIST NEWSGROUPS%c%c", CR, LF); + goto Send_NNTP_command; + } HTAlert(response_text); - else + } else { _HTProgress(response_text); + } NEWS_NETCLOSE(s); s = -1; /* @@ -2215,7 +2523,36 @@ Send_NNTP_command: /* ** Post or load a group, article, etc */ - if (post_wanted || reply_wanted || spost_wanted || sreply_wanted) { + if (status == 480) { + NNTPAuthResult auth_result; + /* + * Some servers return 480 for a failed XGTITLE. - FM + */ + if (list_wanted && !strncmp(command, "XGTITLE", 7) && + strstr(response_text, "uthenticat") == NULL && + strstr(response_text, "uthor") == NULL) { + sprintf(command, "LIST NEWSGROUPS%c%c", CR, LF); + goto Send_NNTP_command; + } + /* + ** Handle Authorization. - FM + */ + if ((auth_result = HTHandleAuthInfo(NewsHost)) == NNTPAUTH_OK) { + goto Send_NNTP_command; + } else if (auth_result == NNTPAUTH_CLOSE) { + if (s != -1 && !(ProxyHost || ProxyHREF)) { + NEWS_NETCLOSE(s); + s = -1; + } + if (retries < 1) + continue; + } + status = HT_NOT_LOADED; + } else if (post_wanted || reply_wanted || + spost_wanted || sreply_wanted) { + /* + ** Handle posting of an article. - FM + */ if (status != 340) { HTAlert("Cannot POST to this host."); if (postfile) { @@ -2232,9 +2569,15 @@ Send_NNTP_command: FREE(postfile); status = HT_NOT_LOADED; } else if (list_wanted) { + /* + ** List available newsgroups. - FM + */ _HTProgress("Reading list of available newsgroups."); status = read_list(ListArg); } else if (group_wanted) { + /* + ** List articles in a news group. - FM + */ if (last < 0) { /* ** We got one article number rather than a range @@ -2252,6 +2595,9 @@ Send_NNTP_command: _HTProgress("Reading list of articles in newsgroup."); status = read_group(groupName, first, last); } else { + /* + ** Get an article from a news group. - FM + */ _HTProgress("Reading news article."); status = read_article(); } @@ -2260,8 +2606,13 @@ Send_NNTP_command: status = HT_LOADED; } if (!(post_wanted || reply_wanted || - spost_wanted || sreply_wanted)) - (*targetClass._free)(target); + spost_wanted || sreply_wanted)) { + if (status == HT_NOT_LOADED) { + (*targetClass._abort)(target, NULL); + } else { + (*targetClass._free)(target); + } + } FREE(NewsHREF); if (ProxyHREF) { StrAllocCopy(NewsHost, ProxyHost); diff --git a/WWW/Library/Implementation/HTStyle.h b/WWW/Library/Implementation/HTStyle.h index 837251aa..99f57e54 100644 --- a/WWW/Library/Implementation/HTStyle.h +++ b/WWW/Library/Implementation/HTStyle.h @@ -104,7 +104,7 @@ typedef struct _HTStyle { */ HTFont font; /* Font id */ HTCoord fontSize; /* The size of font, not independent */ - HTColor color; /* text gray of current run */ + HTColor color; /* text gray of current run */ int superscript; /* superscript (-sub) in points */ HTAnchor *anchor; /* Anchor id if any, else zero */ diff --git a/WWW/Library/Implementation/HTTCP.c b/WWW/Library/Implementation/HTTCP.c index 98d21800..06c9ff03 100644 --- a/WWW/Library/Implementation/HTTCP.c +++ b/WWW/Library/Implementation/HTTCP.c @@ -325,9 +325,15 @@ PUBLIC int HTParseInet ARGS2( struct hostent *phost; /* Pointer to host - See netdb.h */ if (!str) { - if (TRACE) - fprintf(stderr, - "HTParseInet: Can't parse `NULL'.\n"); + if (TRACE) { + fprintf(stderr, "HTParseInet: Can't parse `NULL'.\n"); + } + return -1; + } + if (HTCheckForInterrupt()) { + if (TRACE) { + fprintf (stderr, "HTParseInet: INTERRUPTED for '%s'.\n", str); + } return -1; } StrAllocCopy(host, str); /* Make a copy we can mutilate */ @@ -350,8 +356,11 @@ PUBLIC int HTParseInet ARGS2( } else { #ifdef SUPPRESS /* 1. crashes!?!. 2. Not recommended */ struct servent * serv = getservbyname(port, (char*)0); - if (serv) sin->sin_port = serv->s_port; - else if (TRACE) fprintf(stderr, "TCP: Unknown service %s\n", port); + if (serv) { + sin->sin_port = serv->s_port; + } else if (TRACE) { + fprintf(stderr, "TCP: Unknown service %s\n", port); + } #endif /* SUPPRESS */ } } @@ -363,11 +372,11 @@ PUBLIC int HTParseInet ARGS2( */ sin->sdn_nam.n_len = min(DN_MAXNAML, strlen(host)); /* <=6 in phase 4 */ strncpy (sin->sdn_nam.n_name, host, sin->sdn_nam.n_len + 1); - if (TRACE) + if (TRACE) { fprintf(stderr, "DECnet: Parsed address as object number %d on host %.6s...\n", sin->sdn_objnum, host); - + } #else /* parse Internet host */ if (*host >= '0' && *host <= '9') { /* Test for numeric node address: */ @@ -404,8 +413,10 @@ PUBLIC int HTParseInet ARGS2( FREE(host); } else { /* Alphanumeric node name: */ #ifdef MVS /* Oustanding problem with crash in MVS gethostbyname */ - if (TRACE) - fprintf(stderr, "HTTCP: Calling gethostbyname(%s)\n", host); + if (TRACE) { + fprintf(stderr, + "HTParseInet: Calling gethostbyname(%s)\n", host); + } #endif /* MVS */ #ifdef NSL_FORK @@ -462,8 +473,10 @@ PUBLIC int HTParseInet ARGS2( ** Abort if interrupt key pressed. */ if (HTCheckForInterrupt()) { - if (TRACE) - fprintf (stderr, "*** INTERRUPTED gethostbyname.\n"); + if (TRACE) { + fprintf(stderr, + "HTParseInet: INTERRUPTED gethostbyname.\n"); + } kill(fpid , SIGKILL); FREE(host); close(pfd[0]); @@ -475,26 +488,28 @@ PUBLIC int HTParseInet ARGS2( */ sleep(1); } - if (waitret <= 0) + if (waitret <= 0) { waitret = waitpid(fpid, &cst1, WNOHANG); + } if (TRACE) { if (WIFEXITED(cst1)) { fprintf(stderr, - "NSL_FORK: Child %d exited, status 0x%x.\n", + "HTParseInet: NSL_FORK child %d exited, status 0x%x.\n", (int)waitret, cst1); } else if (WIFSIGNALED(cst1)) { fprintf(stderr, - "NSL_FORK: Child %d got signal, status 0x%x!\n", + "HTParseInet: NSL_FORK child %d got signal, status 0x%x!\n", (int)waitret, cst1); #ifdef WCOREDUMP if (WCOREDUMP(cst1)) { - fprintf(stderr, - "NSL_FORK: Child %d dumped core!\n",(int)waitret); + fprintf(stderr, + "HTParseInet: NSL_FORK child %d dumped core!\n", + (int)waitret); } -#endif +#endif /* WCOREDUMP */ } else if (WIFSTOPPED(cst1)) { fprintf(stderr, - "NSL_FORK: Child %d is stopped, status 0x%x!\n", + "HTParseInet: NSL_FORK child %d is stopped, status 0x%x!\n", (int)waitret, cst1); } } @@ -503,22 +518,28 @@ PUBLIC int HTParseInet ARGS2( */ IOCTL(pfd[0], FIONREAD, &cstat); if (cstat < 4) { - if (TRACE) + if (TRACE) { fprintf(stderr, - "NSL_FORK: Child returns only %d bytes, \ -trying again without forking...\n", cstat); + "HTParseInet: NSL_FORK child returns only %d bytes.\n", + cstat); + fprintf(stderr, + " Trying again without forking.\n"); + } phost = gethostbyname(host); /* See netdb.h */ if (!phost) { - if (TRACE) + if (TRACE) { fprintf(stderr, - "HTParseInet: Can't find internet node name `%s'.\n",host); + "HTParseInet: Can't find internet node name `%s'.\n", + host); + } memset((void *)&sin->sin_addr, 0, sizeof(sin->sin_addr)); } else { - memcpy((void *)&sin->sin_addr, phost->h_addr, phost->h_length); + memcpy((void *)&sin->sin_addr, + phost->h_addr, phost->h_length); } -#if 0 +#ifdef NOTDEFINED cstat = read(pfd[0], (void *)&sin->sin_addr , 4); -#endif +#endif /* NOTDEFINED */ } else { cstat = read(pfd[0], (void *)&sin->sin_addr , cstat); } @@ -526,16 +547,20 @@ trying again without forking...\n", cstat); close(pfd[1]); } if (sin->sin_addr.s_addr == 0) { - if (TRACE) + if (TRACE) { fprintf(stderr, - "HTTPAccess: Can't find internet node name `%s'.\n",host); - FREE(host); - return -1; + "HTParseInet: Can't find internet node name `%s'.\n", + host); + } + FREE(host); + return -1; } FREE(host); #ifdef MVS - if (TRACE) - fprintf(stderr, "HTTCP: gethostbyname() returned %d\n", phost); + if (TRACE) { + fprintf(stderr, + "HTParseInet: gethostbyname() returned %d\n", phost); + } #endif /* MVS */ #else /* Not NSL_FORK: */ @@ -551,13 +576,17 @@ trying again without forking...\n", cstat); #else phost = gethostbyname(host); /* See netdb.h */ #ifdef MVS - if (TRACE) - fprintf(stderr, "HTTCP: gethostbyname() returned %d\n", phost); + if (TRACE) { + fprintf(stderr, + "HTParseInet: gethostbyname() returned %d\n", phost); + } #endif /* MVS */ if (!phost) { - if (TRACE) + if (TRACE) { fprintf(stderr, - "HTTPAccess: Can't find internet node name `%s'.\n",host); + "HTParseInet: Can't find internet node name `%s'.\n", + host); + } FREE(host); return -1; /* Fail? */ } @@ -579,15 +608,15 @@ trying again without forking...\n", cstat); #endif /* NSL_FORK */ } - if (TRACE) + if (TRACE) { fprintf(stderr, - "TCP: Parsed address as port %d, IP address %d.%d.%d.%d\n", + "HTParseInet: Parsed address as port %d, IP address %d.%d.%d.%d\n", (int)ntohs(sin->sin_port), (int)*((unsigned char *)(&sin->sin_addr)+0), (int)*((unsigned char *)(&sin->sin_addr)+1), (int)*((unsigned char *)(&sin->sin_addr)+2), (int)*((unsigned char *)(&sin->sin_addr)+3)); - + } #endif /* Internet vs. Decnet */ return 0; /* OK */ diff --git a/WWW/Library/Implementation/HTTP.c b/WWW/Library/Implementation/HTTP.c index 0bcc2c62..f56f2daa 100644 --- a/WWW/Library/Implementation/HTTP.c +++ b/WWW/Library/Implementation/HTTP.c @@ -261,7 +261,8 @@ try_again: if (pres->rep_out == WWW_PRESENT) { if (pres->rep != WWW_SOURCE && strcasecomp(HTAtom_name(pres->rep), "www/mime") && - strcasecomp(HTAtom_name(pres->rep), "www/compressed")) { + strcasecomp(HTAtom_name(pres->rep), "www/compressed") && + pres->quality <= 1.0 && pres->quality >= 0.0) { if (pres->quality < 1.0) { if (pres->maxbytes > 0) { sprintf(temp, ";q=%4.3f;mxb=%ld", @@ -459,7 +460,7 @@ try_again: } else { if (TRACE) fprintf(stderr, - "HTTP: Not sending authorization (yet)\n"); + "HTTP: Not sending authorization (yet).\n"); } /* ** Add 'Cookie:' header, if it's HTTP or HTTPS @@ -802,14 +803,16 @@ try_again: error_file = fopen(http_error_file, "w"); if (error_file) { /* Managed to open the file */ fprintf(error_file, "error=%d\n", server_status); + fclose(error_file); + } #else error_file = fopen(http_error_file, "a"); if (error_file) { /* Managed to open the file */ fprintf(error_file, " URL=%s (%s)\n", url, METHOD); fprintf(error_file, "STATUS=%s\n", line_buffer); -#endif /* SERVER_STATUS_ONLY */ fclose(error_file); } +#endif /* SERVER_STATUS_ONLY */ } /* @@ -944,11 +947,13 @@ try_again: ** Various forms of Redirection. - FM ** 300 Multiple Choices. ** 301 Moved Permanently. - ** 302 Moved Temporarily. - ** 303 See Other. + ** 302 General (temporary) Redirection (we can, and do, use GET). + ** 303 See Other (always use GET). ** 304 Not Modified. ** 305 Use Proxy. - ** > 305 is unknown. + ** 306 Set Proxy. + ** 307 Temporary Redirect with method retained. + ** > 308 is unknown. */ if (no_url_redirection || do_head || keep_mime_headers) { /* @@ -973,6 +978,20 @@ try_again: * choices (i.e., we use the latter, for now). - FM */ HTAlert(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; } @@ -992,18 +1011,36 @@ try_again: /* * We don't want to compound proxying, so if we * got this from a proxy, just show any message - * to the user. - FM + * to the user. Otherwise, we look for a Location: + * header and use that if present. We should also + * look for a Set-Proxy: header, but that's not yet + * implemented. - FM */ if (using_proxy) { HTAlert("Got redirection to a proxy from the proxy!"); break; } - } else if (server_status > 305) { + } else if (server_status == 306 || server_status > 307) { /* - * Show user the content, if any, for redirection - * statuses we don't know. - FM + * Show user the content, if any, for 306 until we + * implement Set-Proxy: header handling, and for + * redirection statuses we don't know. - FM */ HTAlert(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; } @@ -1015,14 +1052,15 @@ try_again: * If that's another redirecting_url, we'll repeat the * checks, and fetch initiations if acceptible, until * we reach the actual URL, or the redirection limit - * set in HTAccess.c is exceeded. If the status was 301, + * set in HTAccess.c is exceeded. If the status was 301 * indicating that the relocation is permanent, we set * the permanent_redirection flag to make it permanent * for the current anchor tree (i.e., will persist until * the tree is freed or the client exits). If the * redirection would include POST content, we seek - * confirmation from an interactive user, and otherwise - * refuse the redirection. We also don't allow permanent + * confirmation from an interactive user, with option to + * use 303 for 301 (but not for 307), and otherwise refuse + * the redirection. We also don't allow permanent * redirection if we keep POST content. If we don't find * the Location header or it's value is zero-length, we * display whatever the server returned, and the user @@ -1034,7 +1072,10 @@ try_again: char *cp; if ((dump_output_immediately || traversal) && - do_post && server_status != 303) { + do_post && + server_status != 303 && + server_status != 302 && + server_status != 301) { /* * Don't redirect POST content without approval * from an interactive user. - FM @@ -1079,7 +1120,7 @@ try_again: */ if (TRACE) fprintf(stderr, - "HTTP: Have POST content. Treating 301 (Permanent) as 302 (Temporary).\n"); + "HTTP: Have POST content. Treating 301 (Permanent) as Temporary.\n"); HTAlert( "Have POST content. Treating Permanent Redirection as Temporary.\n"); } else { @@ -1347,12 +1388,14 @@ Cookie2_continuation: "HTTP: Proxy URL is '%s'\n", redirecting_url); } - if (!do_post || server_status == 303) { + 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" and - * we can convert to GET, so go back and check - * out the new URL. - FM + * 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; @@ -1361,7 +1404,8 @@ Cookie2_continuation: * Make sure the user wants to redirect * the POST content, or treat as GET - FM & DK */ - switch (HTConfirmPostRedirect(redirecting_url)) { + switch (HTConfirmPostRedirect(redirecting_url, + server_status)) { /* * User failed to confirm. * Abort the fetch. @@ -1413,6 +1457,20 @@ Cookie2_continuation: length = strlen(start_of_data); HTAlert("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; } @@ -1513,6 +1571,15 @@ Cookie2_continuation: break; } else if (!(traversal || dump_output_immediately) && HTConfirm("Show the 407 message body?")) { + 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; } else { if (traversal || dump_output_immediately) @@ -1562,6 +1629,15 @@ Cookie2_continuation: 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; } /* case 4 switch */ break; @@ -1580,6 +1656,20 @@ Cookie2_continuation: ** we always should display. - FM */ HTAlert(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; default: @@ -1595,6 +1685,15 @@ Cookie2_continuation: 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; } /* Switch on server_status/100 */ diff --git a/WWW/Library/Implementation/HTUtils.h b/WWW/Library/Implementation/HTUtils.h index ec013fc5..a0c93655 100644 --- a/WWW/Library/Implementation/HTUtils.h +++ b/WWW/Library/Implementation/HTUtils.h @@ -364,6 +364,8 @@ Sucess (>=0) and failure (<0) codes #define HT_NOT_LOADED -29999 #define HT_OK 0 /* Generic success*/ +#define HT_ERROR -1 /* Generic failure */ + #define HT_NO_ACCESS -10 /* Access not available */ #define HT_FORBIDDEN -11 /* Access forbidden */ #define HT_INTERNAL -12 /* Weird -- should never happen. */ diff --git a/WWW/Library/djgpp/makefile b/WWW/Library/djgpp/makefile index d3cc446e..cf37f9f1 100644 --- a/WWW/Library/djgpp/makefile +++ b/WWW/Library/djgpp/makefile @@ -7,7 +7,7 @@ WWW_MACH = djgpp # The ASIS repository's name for the machine we are on #ASIS_MACH = hardware/os -CFLAGS = -O -DCOLOR_CURSES -DDOSPATH -DNOUSERS -DDEBUG -I../../../djgpp/tcplib/include -I../../../djgpp/tcplib/include/tcp +CFLAGS = -O3 -DEXP_CHARTRANS -DCOLOR_CURSES -DDOSPATH -DNOUSERS -DDEBUG -I../../../djgpp/tcplib/include -I../../../djgpp/tcplib/include/tcp LFLAGS = CC = gcc |