📄 mod_mime_magic.c
字号:
default: /* bogosity, pretend it didn't match */ matched = 0; ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, MODNAME ": mcheck: can't happen: invalid relation %d.", m->reln); break; } return matched;}/* an optimization over plain strcmp() */#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)static int ascmagic(request_rec *r, unsigned char *buf, int nbytes){ int has_escapes = 0; unsigned char *s; char nbuf[HOWMANY + 1]; /* one extra for terminating '\0' */ char *token; register struct names *p; int small_nbytes; /* these are easy, do them first */ /* * for troff, look for . + letter + letter or .\"; this must be done to * disambiguate tar archives' ./file and other trash from real troff * input. */ if (*buf == '.') { unsigned char *tp = buf + 1; while (ap_isspace(*tp)) ++tp; /* skip leading whitespace */ if ((ap_isalnum(*tp) || *tp == '\\') && (ap_isalnum(*(tp + 1)) || *tp == '"')) { magic_rsl_puts(r, "application/x-troff"); return 1; } } if ((*buf == 'c' || *buf == 'C') && ap_isspace(*(buf + 1))) { /* Fortran */ magic_rsl_puts(r, "text/plain"); return 1; } /* look for tokens from names.h - this is expensive!, so we'll limit * ourselves to only SMALL_HOWMANY bytes */ small_nbytes = (nbytes > SMALL_HOWMANY) ? SMALL_HOWMANY : nbytes; /* make a copy of the buffer here because strtok() will destroy it */ s = (unsigned char *) memcpy(nbuf, buf, small_nbytes); s[small_nbytes] = '\0'; has_escapes = (memchr(s, '\033', small_nbytes) != NULL); /* XXX: not multithread safe */ while ((token = strtok((char *) s, " \t\n\r\f")) != NULL) { s = NULL; /* make strtok() keep on tokin' */ for (p = names; p < names + NNAMES; p++) { if (STREQ(p->name, token)) { magic_rsl_puts(r, types[p->type]); if (has_escapes) magic_rsl_puts(r, " (with escape sequences)"); return 1; } } } switch (is_tar(buf, nbytes)) { case 1: /* V7 tar archive */ magic_rsl_puts(r, "application/x-tar"); return 1; case 2: /* POSIX tar archive */ magic_rsl_puts(r, "application/x-tar"); return 1; } /* all else fails, but it is ascii... */ if (has_escapes) { /* text with escape sequences */ /* we leave this open for further differentiation later */ magic_rsl_puts(r, "text/plain"); } else { /* plain text */ magic_rsl_puts(r, "text/plain"); } return 1;}/* * compress routines: zmagic() - returns 0 if not recognized, uncompresses * and prints information if recognized uncompress(s, method, old, n, newch) * - uncompress old into new, using method, return sizeof new */static struct { char *magic; int maglen; char *argv[3]; int silent; char *encoding; /* MUST be lowercase */} compr[] = { { "\037\235", 2, { "uncompress", "-c", NULL }, 0, "x-compress" }, { "\037\213", 2, { "gzip", "-dcq", NULL }, 1, "x-gzip" }, /* * XXX pcat does not work, cause I don't know how to make it read stdin, * so we use gzip */ { "\037\036", 2, { "gzip", "-dcq", NULL }, 0, "x-gzip" },};static int ncompr = sizeof(compr) / sizeof(compr[0]);static int zmagic(request_rec *r, unsigned char *buf, int nbytes){ unsigned char *newbuf; int newsize; int i; for (i = 0; i < ncompr; i++) { if (nbytes < compr[i].maglen) continue; if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0) break; } if (i == ncompr) return 0; if ((newsize = uncompress(r, i, buf, &newbuf, nbytes)) > 0) { tryit(r, newbuf, newsize); /* set encoding type in the request record */ r->content_encoding = compr[i].encoding; } return 1;}struct uncompress_parms { request_rec *r; int method;};static int uncompress_child(void *data, child_info *pinfo){ struct uncompress_parms *parm = data;#if defined(WIN32) int child_pid;#endif if (compr[parm->method].silent) { close(STDERR_FILENO); }#if defined(WIN32) child_pid = spawnvp(compr[parm->method].argv[0], compr[parm->method].argv); return (child_pid);#else execvp(compr[parm->method].argv[0], compr[parm->method].argv); ap_log_rerror(APLOG_MARK, APLOG_ERR, parm->r, MODNAME ": could not execute `%s'.", compr[parm->method].argv[0]); return -1;#endif}static int uncompress(request_rec *r, int method, const unsigned char *old, unsigned char **newch, int n){ struct uncompress_parms parm; BUFF *bin, *bout; pool *sub_pool; parm.r = r; parm.method = method; /* We make a sub_pool so that we can collect our child early, otherwise * there are cases (i.e. generating directory indicies with mod_autoindex) * where we would end up with LOTS of zombies. */ sub_pool = ap_make_sub_pool(r->pool); if (!ap_bspawn_child(sub_pool, uncompress_child, &parm, kill_always, &bin, &bout, NULL)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, MODNAME ": couldn't spawn uncompress process: %s", r->uri); return -1; } if (ap_bwrite(bin, old, n) != n) { ap_destroy_pool(sub_pool); ap_log_rerror(APLOG_MARK, APLOG_ERR, r, MODNAME ": write failed."); return -1; } ap_bclose(bin); *newch = (unsigned char *) ap_palloc(r->pool, n); if ((n = ap_bread(bout, *newch, n)) <= 0) { ap_destroy_pool(sub_pool); ap_log_rerror(APLOG_MARK, APLOG_ERR, r, MODNAME ": read failed %s", r->filename); return -1; } ap_destroy_pool(sub_pool); return n;}/* * is_tar() -- figure out whether file is a tar archive. * * Stolen (by author of file utility) from the public domain tar program: Public * Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu). * * @(#)list.c 1.18 9/23/86 Public Domain - gnu $Id: mod_mime_magic.c,v 1.7 * 1997/06/24 00:41:02 ikluft Exp ikluft $ * * Comments changed and some code/comments reformatted for file command by Ian * Darwin. */#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )/* * Return 0 if the checksum is bad (i.e., probably not a tar archive), 1 for * old UNIX tar file, 2 for Unix Std (POSIX) tar file. */static int is_tar(unsigned char *buf, int nbytes){ register union record *header = (union record *) buf; register int i; register long sum, recsum; register char *p; if (nbytes < sizeof(union record)) return 0; recsum = from_oct(8, header->header.chksum); sum = 0; p = header->charptr; for (i = sizeof(union record); --i >= 0;) { /* * We can't use unsigned char here because of old compilers, e.g. V7. */ sum += 0xFF & *p++; } /* Adjust checksum to count the "chksum" field as blanks. */ for (i = sizeof(header->header.chksum); --i >= 0;) sum -= 0xFF & header->header.chksum[i]; sum += ' ' * sizeof header->header.chksum; if (sum != recsum) return 0; /* Not a tar archive */ if (0 == strcmp(header->header.magic, TMAGIC)) return 2; /* Unix Standard tar archive */ return 1; /* Old fashioned tar archive */}/* * Quick and dirty octal conversion. * * Result is -1 if the field is invalid (all blank, or nonoctal). */static long from_oct(int digs, char *where){ register long value; while (ap_isspace(*where)) { /* Skip spaces */ where++; if (--digs <= 0) return -1; /* All blank field */ } value = 0; while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */ value = (value << 3) | (*where++ - '0'); --digs; } if (digs > 0 && *where && !ap_isspace(*where)) return -1; /* Ended on non-space/nul */ return value;}/* * Check for file-revision suffix * * This is for an obscure document control system used on an intranet. * The web representation of each file's revision has an @1, @2, etc * appended with the revision number. This needs to be stripped off to * find the file suffix, which can be recognized by sending the name back * through a sub-request. The base file name (without the @num suffix) * must exist because its type will be used as the result. */static int revision_suffix(request_rec *r){ int suffix_pos, result; char *sub_filename; request_rec *sub;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": revision_suffix checking %s", r->filename);#endif /* MIME_MAGIC_DEBUG */ /* check for recognized revision suffix */ suffix_pos = strlen(r->filename) - 1; if (!ap_isdigit(r->filename[suffix_pos])) { return 0; } while (suffix_pos >= 0 && ap_isdigit(r->filename[suffix_pos])) suffix_pos--; if (suffix_pos < 0 || r->filename[suffix_pos] != '@') { return 0; } /* perform sub-request for the file name without the suffix */ result = 0; sub_filename = ap_pstrndup(r->pool, r->filename, suffix_pos);#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": subrequest lookup for %s", sub_filename);#endif /* MIME_MAGIC_DEBUG */ sub = ap_sub_req_lookup_file(sub_filename, r); /* extract content type/encoding/language from sub-request */ if (sub->content_type) { r->content_type = ap_pstrdup(r->pool, sub->content_type);#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": subrequest %s got %s", sub_filename, r->content_type);#endif /* MIME_MAGIC_DEBUG */ if (sub->content_encoding) r->content_encoding = ap_pstrdup(r->pool, sub->content_encoding); if (sub->content_language) r->content_language = ap_pstrdup(r->pool, sub->content_language); result = 1; } /* clean up */ ap_destroy_sub_req(sub); return result;}/* * initialize the module */static void magic_init(server_rec *main_server, pool *p){ int result; magic_server_config_rec *conf; magic_server_config_rec *main_conf; server_rec *s;#if MIME_MAGIC_DEBUG struct magic *m, *prevm;#endif /* MIME_MAGIC_DEBUG */ main_conf = ap_get_module_config(main_server->module_config, &mime_magic_module); for (s = main_server; s; s = s->next) { conf = ap_get_module_config(s->module_config, &mime_magic_module); if (conf->magicfile == NULL && s != main_server) { /* inherits from the parent */ *conf = *main_conf; } else if (conf->magicfile) { result = apprentice(s, p); if (result == -1) return;#if MIME_MAGIC_DEBUG prevm = 0; ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, s, MODNAME ": magic_init 1 test"); for (m = conf->magic; m; m = m->next) { if (ap_isprint((((unsigned long) m) >> 24) & 255) && ap_isprint((((unsigned long) m) >> 16) & 255) && ap_isprint((((unsigned long) m) >> 8) & 255) && ap_isprint(((unsigned long) m) & 255)) { ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, s, MODNAME ": magic_init 1: POINTER CLOBBERED! " "m=\"%c%c%c%c\" line=%d", (((unsigned long) m) >> 24) & 255, (((unsigned long) m) >> 16) & 255, (((unsigned long) m) >> 8) & 255, ((unsigned long) m) & 255, prevm ? prevm->lineno : -1); break; } prevm = m; }#endif } }}/* * Find the Content-Type from any resource this module has available */static int magic_find_ct(request_rec *r){ int result; magic_server_config_rec *conf; /* the file has to exist */ if (r->finfo.st_mode == 0 || !r->filename) { return DECLINED; } /* was someone else already here? */ if (r->content_type) { return DECLINED; } conf = ap_get_module_config(r->server->module_config, &mime_magic_module); if (!conf || !conf->magic) { return DECLINED; } /* initialize per-request info */ if (!magic_set_config(r)) { return HTTP_INTERNAL_SERVER_ERROR; } /* try excluding file-revision suffixes */ if (revision_suffix(r) != 1) { /* process it based on the file contents */ if ((result = magic_process(r)) != OK) { return result; } } /* if we have any results, put them in the request structure */ return magic_rsl_to_request(r);}/* * Apache API module interface */module mime_magic_module ={ STANDARD_MODULE_STUFF, magic_init, /* initializer */ NULL, /* dir config creator */ NULL, /* dir merger --- default is to override */ create_magic_server_config, /* server config */ merge_magic_server_config, /* merge server config */ mime_magic_cmds, /* command table */ NULL, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ magic_find_ct, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -