diff options
Diffstat (limited to 'WWW/Library/Implementation')
-rw-r--r-- | WWW/Library/Implementation/HTFTP.c | 5 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTFile.c | 790 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTFile.h | 17 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTFormat.c | 186 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTFormat.h | 23 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTMIME.c | 12 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTParse.c | 58 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTTCP.c | 1 | ||||
-rw-r--r-- | WWW/Library/Implementation/HTTP.c | 36 |
9 files changed, 680 insertions, 448 deletions
diff --git a/WWW/Library/Implementation/HTFTP.c b/WWW/Library/Implementation/HTFTP.c index 6770079c..7c41ab10 100644 --- a/WWW/Library/Implementation/HTFTP.c +++ b/WWW/Library/Implementation/HTFTP.c @@ -3725,10 +3725,13 @@ int HTFTPLoad(const char *name, case cftGzip: StrAllocCopy(anchor->content_encoding, "x-gzip"); break; + case cftDeflate: + StrAllocCopy(anchor->content_encoding, "x-deflate"); + break; case cftBzip2: StrAllocCopy(anchor->content_encoding, "x-bzip2"); break; - default: + case cftNone: break; } } diff --git a/WWW/Library/Implementation/HTFile.c b/WWW/Library/Implementation/HTFile.c index bf10952f..de4c9b6d 100644 --- a/WWW/Library/Implementation/HTFile.c +++ b/WWW/Library/Implementation/HTFile.c @@ -812,6 +812,29 @@ const char *HTFileSuffix(HTAtom *rep, return ""; /* Dunno */ } +/* + * Trim version from VMS filenames to avoid confusing comparisons. + */ +#ifdef VMS +static const char *VMS_trim_version(const char *filename) +{ + const char *result = filename; + char *version = strchr(filename, ';'); + + if (version != 0) { + static char *stripped; + + StrAllocCopy(stripped, filename); + stripped[(const char *) version - filename] = '\0'; + result = (const char *) stripped; + } + return result; +} +#define VMS_DEL_VERSION(name) name = VMS_trim_version(name) +#else +#define VMS_DEL_VERSION(name) /* nothing */ +#endif + /* Determine file format from file name. * ------------------------------------- * @@ -832,9 +855,7 @@ HTFormat HTFileFormat(const char *filename, int i; int lf; -#ifdef VMS - char *semicolon = NULL; -#endif /* VMS */ + VMS_DEL_VERSION(filename); if (pencoding) *pencoding = NULL; @@ -845,15 +866,6 @@ HTFormat HTFileFormat(const char *filename, *pencoding = WWW_ENC_8BIT; return WWW_HTML; } -#ifdef VMS - /* - * Trim at semicolon if a version number was included, so it doesn't - * interfere with the code for getting the MIME type. - FM - */ - if ((semicolon = strchr(filename, ';')) != NULL) - *semicolon = '\0'; -#endif /* VMS */ - #ifndef NO_INIT if (!HTSuffixes) HTFileInit(); @@ -873,10 +885,6 @@ HTFormat HTFileFormat(const char *filename, if (pdesc) *pdesc = suff->desc; if (suff->rep) { -#ifdef VMS - if (semicolon != NULL) - *semicolon = ';'; -#endif /* VMS */ return suff->rep; /* OK -- found */ } for (j = 0; j < n; j++) { /* Got encoding, need representation */ @@ -894,10 +902,6 @@ HTFormat HTFileFormat(const char *filename, *pencoding != WWW_ENC_7BIT && !IsUnityEnc(suff->encoding)) *pencoding = suff->encoding; -#ifdef VMS - if (semicolon != NULL) - *semicolon = ';'; -#endif /* VMS */ return suff->rep; } } @@ -915,13 +919,11 @@ HTFormat HTFileFormat(const char *filename, /* * Set default encoding unless found with suffix already. */ - if (pencoding && !*pencoding) - *pencoding = suff->encoding ? suff->encoding - : HTAtom_for("binary"); -#ifdef VMS - if (semicolon != NULL) - *semicolon = ';'; -#endif /* VMS */ + if (pencoding && !*pencoding) { + *pencoding = (suff->encoding + ? suff->encoding + : HTAtom_for("binary")); + } return suff->rep ? suff->rep : WWW_BINARY; } @@ -1207,6 +1209,8 @@ CompressFileType HTCompressFileType(char *filename, size_t len = strlen(filename); char *ftype = filename + len; + VMS_DEL_VERSION(filename); + if ((len > 4) && !strcasecomp((ftype - 3), "bz2") && strchr(dots, ftype[-4]) != 0) { @@ -1217,6 +1221,11 @@ CompressFileType HTCompressFileType(char *filename, && strchr(dots, ftype[-3]) != 0) { result = cftGzip; ftype -= 3; + } else if ((len > 3) + && !strcasecomp((ftype - 2), "zz") + && strchr(dots, ftype[-3]) != 0) { + result = cftDeflate; + ftype -= 3; } else if ((len > 2) && !strcmp((ftype - 1), "Z") && strchr(dots, ftype[-2]) != 0) { @@ -1225,11 +1234,42 @@ CompressFileType HTCompressFileType(char *filename, } *suffix = ftype; + CTRACE((tfp, "HTCompressFileType(%s) returns %d:%s\n", filename, result, *suffix)); return result; } +/* + * Check if the token from "Content-Encoding" corresponds to a compression + * type. RFC 2068 (and cut/paste into RFC 2616) lists these: + * gzip + * compress + * deflate + * as well as "identity" (but that does nothing). + */ +CompressFileType HTEncodingToCompressType(const char *coding) +{ + CompressFileType result = cftNone; + + if (coding == 0) { + result = cftNone; + } else if (!strcasecomp(coding, "gzip") || + !strcasecomp(coding, "x-gzip")) { + result = cftGzip; + } else if (!strcasecomp(coding, "compress") || + !strcasecomp(coding, "x-compress")) { + result = cftCompress; + } else if (!strcasecomp(coding, "bzip2") || + !strcasecomp(coding, "x-bzip2")) { + result = cftBzip2; + } else if (!strcasecomp(coding, "deflate") || + !strcasecomp(coding, "x-deflate")) { + result = cftDeflate; + } + return result; +} + /* Determine write access to a file. * --------------------------------- * @@ -2079,6 +2119,269 @@ int HTStat(const char *filename, } #endif +#ifdef VMS +#define FOPEN_MODE(bin) "r", "shr=put", "shr=upd" +#define DOT_STRING "._-" /* FIXME: should we check if suffix is after ']' or ':' ? */ +#else +#define FOPEN_MODE(bin) (bin ? BIN_R : "r") +#define DOT_STRING "." +#endif + +static int decompressAndParse(HTParentAnchor *anchor, + HTFormat format_out, + HTStream *sink, + char *nodename GCC_UNUSED, + char *filename, + HTAtom *myEncoding, + HTFormat format, + int *statusp) +{ + HTAtom *encoding = 0; + +#ifdef USE_ZLIB + FILE *zzfp = 0; + gzFile gzfp = 0; +#endif /* USE_ZLIB */ +#ifdef USE_BZLIB + BZFILE *bzfp = 0; +#endif /* USE_ZLIB */ +#if defined(USE_ZLIB) || defined(USE_BZLIB) + CompressFileType internal_decompress = cftNone; + BOOL failed_decompress = NO; +#endif + char *dot = 0; + char *localname = filename; + int bin; + FILE *fp; + +#ifdef VMS + /* + * Assume that the file is in Unix-style syntax if it contains a '/' after + * the leading one. @@ + */ + localname = (strchr(localname + 1, '/') + ? HTVMS_name(nodename, localname) + : localname + 1); +#endif /* VMS */ + + bin = HTCompressFileType(filename, ".", &dot) != cftNone; + fp = fopen(localname, FOPEN_MODE(bin)); + +#ifdef VMS + /* + * If the file wasn't VMS syntax, then perhaps it is Ultrix. + */ + if (!fp) { + char *ultrixname = 0; + + CTRACE((tfp, "HTLoadFile: Can't open as %s\n", localname)); + HTSprintf0(&ultrixname, "%s::\"%s\"", nodename, filename); + fp = fopen(ultrixname, FOPEN_MODE(bin)); + if (!fp) { + CTRACE((tfp, "HTLoadFile: Can't open as %s\n", ultrixname)); + } + FREE(ultrixname); + } +#endif /* VMS */ + CTRACE((tfp, "HTLoadFile: Opening `%s' gives %p\n", localname, fp)); + if (fp) { /* Good! */ + if (HTEditable(localname)) { + HTAtom *put = HTAtom_for("PUT"); + HTList *methods = HTAnchor_methods(anchor); + + if (HTList_indexOf(methods, put) == (-1)) { + HTList_addObject(methods, put); + } + } + /* + * Fake a Content-Encoding for compressed files. - FM + */ + if (!IsUnityEnc(myEncoding)) { + /* + * We already know from the call to HTFileFormat that + * this is a compressed file, no need to look at the filename + * again. - kw + */ + CompressFileType method = HTEncodingToCompressType(HTAtom_name(myEncoding)); + +#define isDOWNLOAD(m) (strcmp(format_out->name, "www/download") && (method == m)) +#ifdef USE_ZLIB + if (isDOWNLOAD(cftGzip)) { + fclose(fp); + gzfp = gzopen(localname, BIN_R); + + CTRACE((tfp, "HTLoadFile: gzopen of `%s' gives %p\n", + localname, gzfp)); + internal_decompress = cftGzip; + } else if (isDOWNLOAD(cftDeflate)) { + zzfp = fp; + fp = 0; + + CTRACE((tfp, "HTLoadFile: zzopen of `%s' gives %p\n", + localname, zzfp)); + internal_decompress = cftDeflate; + } else +#endif /* USE_ZLIB */ +#ifdef USE_BZLIB + if (isDOWNLOAD(cftBzip2)) { + fclose(fp); + bzfp = BZ2_bzopen(localname, BIN_R); + + CTRACE((tfp, "HTLoadFile: bzopen of `%s' gives %p\n", + localname, bzfp)); + internal_decompress = cftBzip2; + } else +#endif /* USE_BZLIB */ + { + StrAllocCopy(anchor->content_type, format->name); + StrAllocCopy(anchor->content_encoding, HTAtom_name(myEncoding)); + format = HTAtom_for("www/compressed"); + } + } else { + CompressFileType cft = HTCompressFileType(localname, DOT_STRING, &dot); + + if (cft != cftNone) { + char *cp = NULL; + + StrAllocCopy(cp, localname); + cp[dot - localname] = '\0'; + format = HTFileFormat(cp, &encoding, NULL); + FREE(cp); + format = HTCharsetFormat(format, anchor, + UCLYhndl_HTFile_for_unspec); + StrAllocCopy(anchor->content_type, format->name); + } + + switch (cft) { + case cftCompress: + StrAllocCopy(anchor->content_encoding, "x-compress"); + format = HTAtom_for("www/compressed"); + break; + case cftDeflate: + StrAllocCopy(anchor->content_encoding, "x-deflate"); +#ifdef USE_ZLIB + if (strcmp(format_out->name, "www/download") != 0) { + zzfp = fp; + fp = 0; + + CTRACE((tfp, "HTLoadFile: zzopen of `%s' gives %p\n", + localname, zzfp)); + internal_decompress = cftDeflate; + } +#else /* USE_ZLIB */ + format = HTAtom_for("www/compressed"); +#endif /* USE_ZLIB */ + break; + case cftGzip: + StrAllocCopy(anchor->content_encoding, "x-gzip"); +#ifdef USE_ZLIB + if (strcmp(format_out->name, "www/download") != 0) { + fclose(fp); + gzfp = gzopen(localname, BIN_R); + + CTRACE((tfp, "HTLoadFile: gzopen of `%s' gives %p\n", + localname, gzfp)); + internal_decompress = cftGzip; + } +#else /* USE_ZLIB */ + format = HTAtom_for("www/compressed"); +#endif /* USE_ZLIB */ + break; + case cftBzip2: + StrAllocCopy(anchor->content_encoding, "x-bzip2"); +#ifdef USE_BZLIB + if (strcmp(format_out->name, "www/download") != 0) { + fclose(fp); + bzfp = BZ2_bzopen(localname, BIN_R); + + CTRACE((tfp, "HTLoadFile: bzopen of `%s' gives %p\n", + localname, bzfp)); + internal_decompress = cftBzip2; + } +#else /* USE_BZLIB */ + format = HTAtom_for("www/compressed"); +#endif /* USE_BZLIB */ + break; + case cftNone: + break; + } + } +#if defined(USE_ZLIB) || defined(USE_BZLIB) + if (internal_decompress != cftNone) { + switch (internal_decompress) { +#ifdef USE_ZLIB + case cftDeflate: + failed_decompress = (zzfp == 0); + break; + case cftCompress: + case cftGzip: + failed_decompress = (gzfp == 0); + break; +#endif +#ifdef USE_BZLIB + case cftBzip2: + failed_decompress = (bzfp == 0); + break; +#endif + default: + failed_decompress = YES; + break; + } + if (failed_decompress) { + *statusp = HTLoadError(NULL, + -(HT_ERROR), + FAILED_OPEN_COMPRESSED_FILE); + } else { + 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); +#ifdef USE_BZLIB + if (bzfp) + *statusp = HTParseBzFile(format, format_out, + anchor, + bzfp, sink); +#endif +#ifdef USE_ZLIB + if (gzfp) + *statusp = HTParseGzFile(format, format_out, + anchor, + gzfp, sink); + else if (zzfp) + *statusp = HTParseZzFile(format, format_out, + anchor, + zzfp, sink); +#endif + } + } else +#endif /* USE_ZLIB || USE_BZLIB */ + { + *statusp = HTParseFile(format, format_out, anchor, fp, sink); + fclose(fp); + } + return TRUE; + } /* If successful open */ + return FALSE; +} + /* Load a document. * ---------------- * @@ -2102,7 +2405,6 @@ int HTLoadFile(const char *addr, HTFormat format; char *nodename = NULL; char *newname = NULL; /* Simplified name of file */ - HTAtom *encoding; /* @@ not used yet */ HTAtom *myEncoding = NULL; /* enc of this file, may be gzip etc. */ int status = -1; char *dot; @@ -2110,16 +2412,6 @@ int HTLoadFile(const char *addr, #ifdef VMS struct stat stat_info; #endif /* VMS */ -#ifdef USE_ZLIB - gzFile gzfp = 0; -#endif /* USE_ZLIB */ -#ifdef USE_BZLIB - BZFILE *bzfp = 0; -#endif /* USE_ZLIB */ -#if defined(USE_ZLIB) || defined(USE_BZLIB) - CompressFileType internal_decompress = cftNone; - BOOL failed_decompress = NO; -#endif /* * Reduce the filename to a basic form (hopefully unique!). @@ -2231,222 +2523,19 @@ int HTLoadFile(const char *addr, } } - /* - * Assume that the file is in Unix-style syntax if it contains a '/' after - * the leading one. @@ - */ - { - FILE *fp; - char *vmsname = strchr(filename + 1, '/') ? - HTVMS_name(nodename, filename) : filename + 1; - - fp = fopen(vmsname, "r", "shr=put", "shr=upd"); - - /* - * If the file wasn't VMS syntax, then perhaps it is Ultrix. - */ - if (!fp) { - char *ultrixname = 0; - - CTRACE((tfp, "HTLoadFile: Can't open as %s\n", vmsname)); - HTSprintf0(&ultrixname, "%s::\"%s\"", nodename, filename); - fp = fopen(ultrixname, "r", "shr=put", "shr=upd"); - if (!fp) { - CTRACE((tfp, "HTLoadFile: Can't open as %s\n", - ultrixname)); - } - FREE(ultrixname); - } - if (fp) { - char *semicolon = NULL; - - if (HTEditable(vmsname)) { - HTAtom *put = HTAtom_for("PUT"); - HTList *methods = HTAnchor_methods(anchor); - - if (HTList_indexOf(methods, put) == (-1)) { - HTList_addObject(methods, put); - } - } - /* - * Trim vmsname at semicolon if a version number was included, so - * it doesn't interfere with the check for a compressed file. - FM - */ - if ((semicolon = strchr(vmsname, ';')) != NULL) - *semicolon = '\0'; - /* - * Fake a Content-Encoding for compressed files. - FM - */ - if (!IsUnityEnc(myEncoding)) { - /* - * We already know from the call to HTFileFormat above that - * this is a compressed file, no need to look at the filename - * again. - kw - */ -#ifdef USE_ZLIB - if (strcmp(format_out->name, "www/download") != 0 && - (!strcmp(HTAtom_name(myEncoding), "gzip") || - !strcmp(HTAtom_name(myEncoding), "x-gzip"))) { - fclose(fp); - if (semicolon != NULL) - *semicolon = ';'; - gzfp = gzopen(vmsname, BIN_R); - - CTRACE((tfp, "HTLoadFile: gzopen of `%s' gives %p\n", - vmsname, (void *) gzfp)); - internal_decompress = cftGzip; - } else -#endif /* USE_ZLIB */ -#ifdef USE_BZLIB - if (strcmp(format_out->name, "www/download") != 0 && - (!strcmp(HTAtom_name(myEncoding), "bzip2") || - !strcmp(HTAtom_name(myEncoding), "x-bzip2"))) { - fclose(fp); - if (semicolon != NULL) - *semicolon = ';'; - bzfp = BZ2_bzopen(vmsname, BIN_R); - - CTRACE((tfp, "HTLoadFile: bzopen of `%s' gives %p\n", - vmsname, (void *) bzfp)); - use_zread = YES; - } else -#endif /* USE_BZLIB */ - { - StrAllocCopy(anchor->content_type, format->name); - StrAllocCopy(anchor->content_encoding, HTAtom_name(myEncoding)); - format = HTAtom_for("www/compressed"); - } - } else { - /* FIXME: should we check if suffix is after ']' or ':' ? */ - CompressFileType cft = HTCompressFileType(vmsname, "._-", &dot); - - if (cft != cftNone) { - char *cp = NULL; - - StrAllocCopy(cp, vmsname); - cp[dot - vmsname] = '\0'; - format = HTFileFormat(cp, &encoding, NULL); - FREE(cp); - format = HTCharsetFormat(format, anchor, - UCLYhndl_HTFile_for_unspec); - StrAllocCopy(anchor->content_type, format->name); - } - - switch (cft) { - case cftCompress: - StrAllocCopy(anchor->content_encoding, "x-compress"); - format = HTAtom_for("www/compressed"); - break; - case cftGzip: - StrAllocCopy(anchor->content_encoding, "x-gzip"); -#ifdef USE_ZLIB - if (strcmp(format_out->name, "www/download") != 0) { - fclose(fp); - if (semicolon != NULL) - *semicolon = ';'; - gzfp = gzopen(vmsname, BIN_R); - - CTRACE((tfp, "HTLoadFile: gzopen of `%s' gives %p\n", - vmsname, (void *) gzfp)); - internal_decompress = cftGzip; - } -#else /* USE_ZLIB */ - format = HTAtom_for("www/compressed"); -#endif /* USE_ZLIB */ - break; - case cftBzip2: - StrAllocCopy(anchor->content_encoding, "x-bzip2"); -#ifdef USE_BZLIB - if (strcmp(format_out->name, "www/download") != 0) { - fclose(fp); - if (semicolon != NULL) - *semicolon = ';'; - bzfp = BZ2_bzopen(vmsname, BIN_R); - - CTRACE((tfp, "HTLoadFile: bzopen of `%s' gives %p\n", - vmsname, (void *) bzfp)); - internal_decompress = cfgBzip2; - } -#else /* USE_BZLIB */ - format = HTAtom_for("www/compressed"); -#endif /* USE_BZLIB */ - break; - case cftNone: - break; - } - } - if (semicolon != NULL) - *semicolon = ';'; - FREE(filename); - FREE(nodename); -#if defined(USE_ZLIB) || defined(USE_BZLIB) - if (internal_decompress != cftNone) { - switch (internal_decompress) { -#ifdef USE_ZLIB - case cftCompress: - case cftGzip: - failed_decompress = (gzfp == 0); - break; -#endif -#ifdef USE_BZLIB - case cftBzip2: - failed_decompress = (bzfp == 0); - break; -#endif - default: - failed_decompress = YES; - break; - } - if (failed_decompress) { - status = HTLoadError(NULL, - -(HT_ERROR), - FAILED_OPEN_COMPRESSED_FILE); - } else { - 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); -#ifdef USE_BZLIB - if (bzfp) - status = HTParseBzFile(format, format_out, - anchor, - bzfp, sink); -#endif -#ifdef USE_ZLIB - if (gzfp) - status = HTParseGzFile(format, format_out, - anchor, - gzfp, sink); -#endif - } - } else -#endif /* USE_ZLIB || USE_BZLIB */ - { - status = HTParseFile(format, format_out, anchor, fp, sink); - fclose(fp); - } - return status; - } /* If successful open */ + if (decompressAndParse(anchor, + format_out, + sink, + nodename, + filename, + myEncoding, + format, + &status)) { + FREE(nodename); FREE(filename); + return status; } + FREE(filename); #else /* not VMS: */ @@ -2540,6 +2629,9 @@ int HTLoadFile(const char *addr, case cftGzip: atomname = "application/x-gzip"; break; + case cftDeflate: + atomname = "application/x-deflate"; + break; case cftBzip2: atomname = "application/x-bzip2"; break; @@ -2678,184 +2770,19 @@ int HTLoadFile(const char *addr, /* End of directory reading section */ #endif /* HAVE_READDIR */ - { - int bin = HTCompressFileType(localname, ".", &dot) != cftNone; - FILE *fp = fopen(localname, (bin ? BIN_R : "r")); - - CTRACE((tfp, "HTLoadFile: Opening `%s' gives %p\n", - localname, (void *) fp)); - if (fp) { /* Good! */ - if (HTEditable(localname)) { - HTAtom *put = HTAtom_for("PUT"); - HTList *methods = HTAnchor_methods(anchor); - - if (HTList_indexOf(methods, put) == (-1)) { - HTList_addObject(methods, put); - } - } - /* - * Fake a Content-Encoding for compressed files. - FM - */ - if (!IsUnityEnc(myEncoding)) { - /* - * We already know from the call to HTFileFormat above that - * this is a compressed file, no need to look at the - * filename again. - kw - */ -#ifdef USE_ZLIB - if (strcmp(format_out->name, "www/download") != 0 && - (!strcmp(HTAtom_name(myEncoding), "gzip") || - !strcmp(HTAtom_name(myEncoding), "x-gzip"))) { - fclose(fp); - gzfp = gzopen(localname, BIN_R); - - CTRACE((tfp, "HTLoadFile: gzopen of `%s' gives %p\n", - localname, (void *) gzfp)); - internal_decompress = cftGzip; - } else -#endif /* USE_ZLIB */ -#ifdef USE_BZLIB - if (strcmp(format_out->name, "www/download") != 0 && - (!strcmp(HTAtom_name(myEncoding), "bzip2") || - !strcmp(HTAtom_name(myEncoding), "x-bzip2"))) { - fclose(fp); - bzfp = BZ2_bzopen(localname, BIN_R); - - CTRACE((tfp, "HTLoadFile: bzopen of `%s' gives %p\n", - localname, (void *) bzfp)); - internal_decompress = cftBzip2; - } else -#endif /* USE_BZLIB */ - { - StrAllocCopy(anchor->content_type, format->name); - StrAllocCopy(anchor->content_encoding, HTAtom_name(myEncoding)); - format = HTAtom_for("www/compressed"); - } - } else { - CompressFileType cft = HTCompressFileType(localname, ".", &dot); - - if (cft != cftNone) { - char *cp = NULL; - - StrAllocCopy(cp, localname); - cp[dot - localname] = '\0'; - format = HTFileFormat(cp, &encoding, NULL); - FREE(cp); - format = HTCharsetFormat(format, anchor, - UCLYhndl_HTFile_for_unspec); - StrAllocCopy(anchor->content_type, format->name); - } - - switch (cft) { - case cftCompress: - StrAllocCopy(anchor->content_encoding, "x-compress"); - format = HTAtom_for("www/compressed"); - break; - case cftGzip: - StrAllocCopy(anchor->content_encoding, "x-gzip"); -#ifdef USE_ZLIB - if (strcmp(format_out->name, "www/download") != 0) { - fclose(fp); - gzfp = gzopen(localname, BIN_R); - - CTRACE((tfp, - "HTLoadFile: gzopen of `%s' gives %p\n", - localname, (void *) gzfp)); - internal_decompress = cftGzip; - } -#else /* USE_ZLIB */ - format = HTAtom_for("www/compressed"); -#endif /* USE_ZLIB */ - break; - case cftBzip2: - StrAllocCopy(anchor->content_encoding, "x-bzip2"); -#ifdef USE_BZLIB - if (strcmp(format_out->name, "www/download") != 0) { - fclose(fp); - bzfp = BZ2_bzopen(localname, BIN_R); - - CTRACE((tfp, - "HTLoadFile: bzopen of `%s' gives %p\n", - localname, (void *) bzfp)); - internal_decompress = cftBzip2; - } -#else /* USE_BZLIB */ - format = HTAtom_for("www/compressed"); -#endif /* USE_BZLIB */ - break; - case cftNone: - break; - } - } - FREE(localname); - FREE(nodename); -#if defined(USE_ZLIB) || defined(USE_BZLIB) - if (internal_decompress != cftNone) { - switch (internal_decompress) { -#ifdef USE_ZLIB - case cftGzip: - failed_decompress = (gzfp == 0); - break; -#endif -#ifdef USE_BZLIB - case cftBzip2: - failed_decompress = (bzfp == 0); - break; -#endif - default: - failed_decompress = YES; - break; - } - if (failed_decompress) { - status = HTLoadError(NULL, - -(HT_ERROR), - FAILED_OPEN_COMPRESSED_FILE); - } else { - 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); -#ifdef USE_BZLIB - if (bzfp) - status = HTParseBzFile(format, format_out, - anchor, - bzfp, sink); -#endif -#ifdef USE_ZLIB - if (gzfp) - status = HTParseGzFile(format, format_out, - anchor, - gzfp, sink); -#endif - } - } else -#endif /* USE_ZLIB */ - { - status = HTParseFile(format, format_out, anchor, fp, sink); - fclose(fp); - } - return status; - } /* If successful open */ + if (decompressAndParse(anchor, + format_out, + sink, + nodename, + localname, + myEncoding, + format, + &status)) { + FREE(nodename); FREE(localname); - } /* scope of fp */ + return status; + } + FREE(localname); } /* local unix file system */ #endif /* !NO_UNIX_IO */ #endif /* VMS */ @@ -2966,6 +2893,11 @@ void HTInitProgramPaths(void) path = GZIP_PATH; break; #endif +#ifdef INFLATE_PATH + case ppINFLATE: + path = INFLATE_PATH; + break; +#endif #ifdef INSTALL_PATH case ppINSTALL: path = INSTALL_PATH; diff --git a/WWW/Library/Implementation/HTFile.h b/WWW/Library/Implementation/HTFile.h index 8c522b64..0c69bb42 100644 --- a/WWW/Library/Implementation/HTFile.h +++ b/WWW/Library/Implementation/HTFile.h @@ -192,20 +192,34 @@ extern void LYGetFileInfo(const char *filename, extern float HTFileValue(const char *filename); /* - * Determine compression type from file name, by looking at its suffix. + * Known compression types. */ typedef enum { cftNone ,cftCompress ,cftGzip ,cftBzip2 + ,cftDeflate } CompressFileType; +/* + * Determine compression type from file name, by looking at its suffix. + */ extern CompressFileType HTCompressFileType(char *filename, char *dots, char **suffix); /* + * Determine compression type from the content-type. + */ +extern CompressFileType HTContentToCompressType(const char *encoding); + +/* + * Determine compression type from the content-encoding. + */ +extern CompressFileType HTEncodingToCompressType(const char *encoding); + +/* * Determine write access to a file. * * ON EXIT, @@ -276,6 +290,7 @@ typedef enum { ,ppCOPY ,ppCSWING ,ppGZIP + ,ppINFLATE ,ppINSTALL ,ppMKDIR ,ppMV diff --git a/WWW/Library/Implementation/HTFormat.c b/WWW/Library/Implementation/HTFormat.c index fa9bc045..bdcdef17 100644 --- a/WWW/Library/Implementation/HTFormat.c +++ b/WWW/Library/Implementation/HTFormat.c @@ -436,7 +436,7 @@ static HTPresentation *HTFindPresentation(HTFormat rep_in, if (failsMailcap(pres, anchor)) continue; last_default_match = pres; - /* otherwise use the first one */ + /* otherwise use the first one */ } } } @@ -1084,6 +1084,122 @@ static int HTGzFileCopy(gzFile gzfp, HTStream *sink) HTFinishDisplayPartial(); return rv; } + +/* Push data from a deflate file pointer down a stream + * ------------------------------------- + * + * This routine is responsible for creating and PRESENTING any + * graphic (or other) objects described by the file. The code is + * loosely based on the inflate.c file from w3m. + * + * + * State of file and target stream on entry: + * FILE (zzfp) assumed open (should have deflated content), + * target (sink) assumed valid. + * + * Return values: + * HT_INTERRUPTED Interruption after some data read. + * HT_PARTIAL_CONTENT Error after some data read. + * -1 Error before any data read. + * HT_LOADED Normal end of file indication on reading. + * + * State of file and target stream on return: + * always zzfp still open, target stream still valid. + */ +static int HTZzFileCopy(FILE *zzfp, HTStream *sink) +{ + static char dummy_head[1 + 1] = + { + 0x8 + 0x7 * 0x10, + (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF, + }; + + z_stream s; + HTStreamClass targetClass; + int bytes; + int rv = HT_OK; + char output_buffer[INPUT_BUFFER_SIZE]; + int status; + int flush; + int retry = 0; + int len = 0; + + /* Push the data down the stream + */ + targetClass = *(sink->isa); /* Copy pointers to procedures */ + + s.zalloc = Z_NULL; + s.zfree = Z_NULL; + s.opaque = Z_NULL; + status = inflateInit(&s); + if (status != Z_OK) { + CTRACE((tfp, "HTZzFileCopy inflateInit() %s\n", zError(status))); + exit(1); + } + s.avail_in = 0; + s.next_out = (Bytef *) output_buffer; + s.avail_out = sizeof(output_buffer); + flush = Z_NO_FLUSH; + + /* read and inflate deflate'd file, and push binary down sink + */ + HTReadProgress(bytes = 0, 0); + for (;;) { + if (s.avail_in == 0) { + s.next_in = (Bytef *) input_buffer; + len = s.avail_in = fread(input_buffer, 1, INPUT_BUFFER_SIZE, zzfp); + } + status = inflate(&s, flush); + if (status == Z_STREAM_END || status == Z_BUF_ERROR) { + len = sizeof(output_buffer) - s.avail_out; + if (len > 0) { + (*targetClass.put_block) (sink, output_buffer, len); + bytes += len; + HTReadProgress(bytes, -1); + HTDisplayPartial(); + } + rv = HT_LOADED; + break; + } else if (status == Z_DATA_ERROR && !retry++) { + status = inflateReset(&s); + if (status != Z_OK) { + CTRACE((tfp, "HTZzFileCopy inflateReset() %s\n", zError(status))); + rv = bytes ? HT_PARTIAL_CONTENT : -1; + break; + } + s.next_in = (Bytef *) dummy_head; + s.avail_in = sizeof(dummy_head); + status = inflate(&s, flush); + s.next_in = (Bytef *) input_buffer; + s.avail_in = len; + continue; + } else if (status != Z_OK) { + CTRACE((tfp, "HTZzFileCopy inflate() %s\n", zError(status))); + rv = bytes ? HT_PARTIAL_CONTENT : -1; + break; + } else if (s.avail_out == 0) { + len = sizeof(output_buffer); + s.next_out = (Bytef *) output_buffer; + s.avail_out = sizeof(output_buffer); + + (*targetClass.put_block) (sink, output_buffer, len); + bytes += len; + HTReadProgress(bytes, -1); + HTDisplayPartial(); + + if (HTCheckForInterrupt()) { + _HTProgress(TRANSFER_INTERRUPTED); + rv = bytes ? HT_INTERRUPTED : -1; + break; + } + } + retry = 1; + } /* next bufferload */ + + inflateEnd(&s); + HTFinishDisplayPartial(); + return rv; +} #endif /* USE_ZLIB */ #ifdef USE_BZLIB @@ -1480,6 +1596,74 @@ int HTParseGzFile(HTFormat rep_in, else return HT_LOADED; } + +/* HTParseZzFile + * + * State of file and target stream on entry: + * FILE (zzfp) assumed open, + * target (sink) usually NULL (will call stream stack). + * + * Return values: + * -501 Stream stack failed (cannot present or convert). + * -1 Download cancelled. + * HT_NO_DATA Error before any data read. + * HT_PARTIAL_CONTENT Interruption or error after some data read. + * HT_LOADED Normal end of file indication on reading. + * + * State of file and target stream on return: + * always zzfp closed; target freed, aborted, or NULL. + */ +int HTParseZzFile(HTFormat rep_in, + HTFormat format_out, + HTParentAnchor *anchor, + FILE *zzfp, + HTStream *sink) +{ + HTStream *stream; + HTStreamClass targetClass; + int rv; + + stream = HTStreamStack(rep_in, format_out, sink, anchor); + + if (!stream) { + char *buffer = 0; + + fclose(zzfp); + if (LYCancelDownload) { + LYCancelDownload = FALSE; + return -1; + } + HTSprintf0(&buffer, CANNOT_CONVERT_I_TO_O, + HTAtom_name(rep_in), HTAtom_name(format_out)); + CTRACE((tfp, "HTFormat(in HTParseGzFile): %s\n", buffer)); + rv = HTLoadError(sink, 501, buffer); + FREE(buffer); + return rv; + } + + /* + * Push the data down the stream + * + * @@ Bug: This decision ought to be made based on "encoding" rather than + * on content-type. @@@ When we handle encoding. The current method + * smells anyway. + */ + targetClass = *(stream->isa); /* Copy pointers to procedures */ + rv = HTZzFileCopy(zzfp, stream); + if (rv == -1 || rv == HT_INTERRUPTED) { + (*targetClass._abort) (stream, NULL); + } else { + (*targetClass._free) (stream); + } + + fclose(zzfp); + 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 */ #ifdef USE_BZLIB diff --git a/WWW/Library/Implementation/HTFormat.h b/WWW/Library/Implementation/HTFormat.h index ec51e7d6..ad3df250 100644 --- a/WWW/Library/Implementation/HTFormat.h +++ b/WWW/Library/Implementation/HTFormat.h @@ -218,9 +218,13 @@ typedef enum { typedef enum { encodingNONE = 0 ,encodingGZIP = 1 - ,encodingCOMPRESS = 2 - ,encodingBZIP2 = 4 - ,encodingALL = encodingGZIP + encodingCOMPRESS + encodingBZIP2 + ,encodingDEFLATE = 2 + ,encodingCOMPRESS = 4 + ,encodingBZIP2 = 8 + ,encodingALL = (encodingGZIP + + encodingDEFLATE + + encodingCOMPRESS + + encodingBZIP2) } AcceptEncoding; /* @@ -482,6 +486,19 @@ extern int HTParseGzFile(HTFormat format_in, gzFile gzfp, HTStream *sink); +/* +HTParseZzFile: Parse a deflate'd File through a file pointer + + This routine is called by protocols modules to load an object. uses + HTStreamStack and HTZzFileCopy. Returns HT_LOADED if successful, can also + return HT_PARTIAL_CONTENT, HT_NO_DATA, or other <0 for failure. + */ +extern int HTParseZzFile(HTFormat format_in, + HTFormat format_out, + HTParentAnchor *anchor, + FILE *zzfp, + HTStream *sink); + #endif /* USE_ZLIB */ #ifdef USE_BZLIB diff --git a/WWW/Library/Implementation/HTMIME.c b/WWW/Library/Implementation/HTMIME.c index efa54e4e..49791955 100644 --- a/WWW/Library/Implementation/HTMIME.c +++ b/WWW/Library/Implementation/HTMIME.c @@ -15,6 +15,7 @@ #include <HTMIME.h> /* Implemented here */ #include <HTTP.h> /* for redirecting_url */ #include <HTAlert.h> +#include <HTFile.h> #include <HTCJK.h> #include <UCMap.h> #include <UCDefs.h> @@ -168,14 +169,17 @@ void HTMIME_TrimDoubleQuotes(char *value) value[i] = cp[(i + 1)]; } +/* + * Check if the token from "Content-Encoding" corresponds to a compression + * type. + */ static BOOL content_is_compressed(HTStream *me) { char *encoding = me->anchor->content_encoding; + BOOL result = (HTEncodingToCompressType(encoding) != cftNone); - return encoding != 0 - && strcmp(encoding, "8bit") != 0 - && strcmp(encoding, "7bit") != 0 - && strcmp(encoding, "binary") != 0; + CTRACE((tfp, "content is%s compressed\n", result ? "" : " NOT")); + return result; } /* diff --git a/WWW/Library/Implementation/HTParse.c b/WWW/Library/Implementation/HTParse.c index e894b55c..70a21573 100644 --- a/WWW/Library/Implementation/HTParse.c +++ b/WWW/Library/Implementation/HTParse.c @@ -29,6 +29,24 @@ struct struct_parts { char *anchor; }; +#if 0 /* for debugging */ +static void show_parts(const char *name, struct struct_parts *parts, int line) +{ + if (TRACE) { + CTRACE((tfp, "struct_parts(%s) %s@%d\n", name, __FILE__, line)); + CTRACE((tfp, " access '%s'\n", NONNULL(parts->access))); + CTRACE((tfp, " host '%s'\n", NONNULL(parts->host))); + CTRACE((tfp, " absolute '%s'\n", NONNULL(parts->absolute))); + CTRACE((tfp, " relative '%s'\n", NONNULL(parts->relative))); + CTRACE((tfp, " search '%s'\n", NONNULL(parts->search))); + CTRACE((tfp, " anchor '%s'\n", NONNULL(parts->anchor))); + } +} +#define SHOW_PARTS(name) show_parts(#name, &name, __LINE__) +#else +#define SHOW_PARTS(name) /* nothing */ +#endif + /* Strip white space off a string. HTStrip() * ------------------------------- * @@ -163,6 +181,16 @@ static void scan(char *name, #define LYalloca_free(x) free(x) #endif +static char *strchr_or_end(char *string, int ch) +{ + char *result = strchr(string, ch); + + if (result == 0) { + result = string + strlen(string); + } + return result; +} + /* Parse a Name relative to another name. HTParse() * -------------------------------------- * @@ -187,7 +215,7 @@ char *HTParse(const char *aName, int len, len1, len2; char *name = NULL; char *rel = NULL; - char *p; + char *p, *q; char *acc_method; struct struct_parts given, related; @@ -236,6 +264,7 @@ char *HTParse(const char *aName, * Cut up the string into URL fields. */ scan(name, &given); + SHOW_PARTS(given); /* * Now related string. @@ -254,6 +283,7 @@ char *HTParse(const char *aName, memcpy(rel, relatedName, len2); scan(rel, &related); } + SHOW_PARTS(related); /* * Handle the scheme (access) field. @@ -450,12 +480,24 @@ char *HTParse(const char *aName, *tail++ = '/'; strcpy(tail, related.absolute); if (given.relative) { - p = strchr(tail, '?'); /* Search part? */ - if (p == NULL) - p = (tail + strlen(tail) - 1); - for (; *p != '/'; p--) ; /* last / */ - p[1] = '\0'; /* Remove filename */ - strcat(p, given.relative); /* Add given one */ + /* RFC 1808 part 4 step 5 (if URL path is empty) */ + /* a) if given has params, add/replace that */ + if (given.relative[0] == ';') { + strcpy(strchr_or_end(tail, ';'), given.relative); + } + /* b) if given has query, add/replace that */ + else if (given.relative[0] == '?') { + strcpy(strchr_or_end(tail, '?'), given.relative); + } + /* otherwise fall through to RFC 1808 part 4 step 6 */ + else { + p = strchr(tail, '?'); /* Search part? */ + if (p == NULL) + p = (tail + strlen(tail) - 1); + for (; *p != '/'; p--) ; /* last / */ + p[1] = '\0'; /* Remove filename */ + strcat(p, given.relative); /* Add given one */ + } HTSimplify(result); } CTRACE((tfp, "HTParse: (Related-ABS)\n")); @@ -536,7 +578,7 @@ char *HTParse(const char *aName, default: CTRACE((tfp, "HTParse: encode:`%s'\n", result)); do { - char *q = p + strlen(p) + 2; + q = p + strlen(p) + 2; while (q != p + 1) { q[0] = q[-2]; diff --git a/WWW/Library/Implementation/HTTCP.c b/WWW/Library/Implementation/HTTCP.c index b5574926..84aeb412 100644 --- a/WWW/Library/Implementation/HTTCP.c +++ b/WWW/Library/Implementation/HTTCP.c @@ -1390,6 +1390,7 @@ static LYNX_ADDRINFO *HTGetAddrInfo(const char *str, res = NULL; } + free(s); return res; } #endif /* INET6 */ diff --git a/WWW/Library/Implementation/HTTP.c b/WWW/Library/Implementation/HTTP.c index ab12eb2b..7307ebb1 100644 --- a/WWW/Library/Implementation/HTTP.c +++ b/WWW/Library/Implementation/HTTP.c @@ -353,6 +353,40 @@ static void strip_userid(char *host) } } +/* + * Check if the user's options specified to use the given encoding. Normally + * all encodings with compiled-in support are specified (encodingALL). + */ +static BOOL acceptEncoding (int code) +{ + BOOL result = FALSE; + if ((code & LYAcceptEncoding) != 0) { + const char *program = 0; + switch (code) { + case encodingGZIP: + program = HTGetProgramPath(ppGZIP); + break; + case encodingDEFLATE: + program = HTGetProgramPath(ppINFLATE); + break; + case encodingCOMPRESS: + program = HTGetProgramPath(ppCOMPRESS); + break; + case encodingBZIP2: + program = HTGetProgramPath(ppBZIP2); + break; + default: + break; + } + /* + * FIXME: if lynx did not rely upon external programs to decompress + * files for external viewers, this check could be relaxed. + */ + result = (program != 0); + } + return result; +} + /* Load Document from HTTP Server HTLoadHTTP() * ============================== * @@ -745,7 +779,7 @@ static int HTLoadHTTP(const char *arg, int j, k; for (j = 1; j < encodingALL; j <<= 1) { - if ((j & LYAcceptEncoding) != 0) { + if (acceptEncoding(j)) { for (k = 0; tbl_preferred_encoding[k].name != 0; ++k) { if (tbl_preferred_encoding[k].value == j) { if (list != 0) |