📄 mod_mime_magic.c
字号:
/* * configuration functions - called by Apache API routines */module mime_magic_module;static void *create_magic_server_config(pool *p, server_rec *d){ /* allocate the config - use pcalloc because it needs to be zeroed */ return ap_pcalloc(p, sizeof(magic_server_config_rec));}static void *merge_magic_server_config(pool *p, void *basev, void *addv){ magic_server_config_rec *base = (magic_server_config_rec *) basev; magic_server_config_rec *add = (magic_server_config_rec *) addv; magic_server_config_rec *new = (magic_server_config_rec *) ap_palloc(p, sizeof(magic_server_config_rec)); new->magicfile = add->magicfile ? add->magicfile : base->magicfile; new->magic = NULL; new->last = NULL; return new;}static const char *set_magicfile(cmd_parms *cmd, char *d, char *arg){ magic_server_config_rec *conf = (magic_server_config_rec *) ap_get_module_config(cmd->server->module_config, &mime_magic_module); if (!conf) { return MODNAME ": server structure not allocated"; } conf->magicfile = arg; return NULL;}/* * configuration file commands - exported to Apache API */static const command_rec mime_magic_cmds[] ={ {"MimeMagicFile", set_magicfile, NULL, RSRC_CONF, TAKE1, "Path to MIME Magic file (in file(1) format)"}, {NULL}};/* * RSL (result string list) processing routines * * These collect strings that would have been printed in fragments by file(1) * into a list of magic_rsl structures with the strings. When complete, * they're concatenated together to become the MIME content and encoding * types. * * return value conventions for these functions: functions which return int: * failure = -1, other = result functions which return pointers: failure = 0, * other = result *//* allocate a per-request structure and put it in the request record */static magic_req_rec *magic_set_config(request_rec *r){ magic_req_rec *req_dat = (magic_req_rec *) ap_palloc(r->pool, sizeof(magic_req_rec)); req_dat->head = req_dat->tail = (magic_rsl *) NULL; ap_set_module_config(r->request_config, &mime_magic_module, req_dat); return req_dat;}/* add a string to the result string list for this request *//* it is the responsibility of the caller to allocate "str" */static int magic_rsl_add(request_rec *r, char *str){ magic_req_rec *req_dat = (magic_req_rec *) ap_get_module_config(r->request_config, &mime_magic_module); magic_rsl *rsl; /* make sure we have a list to put it in */ if (!req_dat) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, MODNAME ": request config should not be NULL"); if (!(req_dat = magic_set_config(r))) { /* failure */ return -1; } } /* allocate the list entry */ rsl = (magic_rsl *) ap_palloc(r->pool, sizeof(magic_rsl)); /* fill it */ rsl->str = str; rsl->next = (magic_rsl *) NULL; /* append to the list */ if (req_dat->head && req_dat->tail) { req_dat->tail->next = rsl; req_dat->tail = rsl; } else { req_dat->head = req_dat->tail = rsl; } /* success */ return 0;}/* RSL hook for puts-type functions */static int magic_rsl_puts(request_rec *r, char *str){ return magic_rsl_add(r, str);}/* RSL hook for printf-type functions */static int magic_rsl_printf(request_rec *r, char *str,...){ va_list ap; char buf[MAXMIMESTRING]; /* assemble the string into the buffer */ va_start(ap, str); ap_vsnprintf(buf, sizeof(buf), str, ap); va_end(ap); /* add the buffer to the list */ return magic_rsl_add(r, strdup(buf));}/* RSL hook for putchar-type functions */static int magic_rsl_putchar(request_rec *r, char c){ char str[2]; /* high overhead for 1 char - just hope they don't do this much */ str[0] = c; str[1] = '\0'; return magic_rsl_add(r, str);}/* allocate and copy a contiguous string from a result string list */static char *rsl_strdup(request_rec *r, int start_frag, int start_pos, int len){ char *result; /* return value */ int cur_frag, /* current fragment number/counter */ cur_pos, /* current position within fragment */ res_pos; /* position in result string */ magic_rsl *frag; /* list-traversal pointer */ magic_req_rec *req_dat = (magic_req_rec *) ap_get_module_config(r->request_config, &mime_magic_module); /* allocate the result string */ result = (char *) ap_palloc(r->pool, len + 1); /* loop through and collect the string */ res_pos = 0; for (frag = req_dat->head, cur_frag = 0; frag->next; frag = frag->next, cur_frag++) { /* loop to the first fragment */ if (cur_frag < start_frag) continue; /* loop through and collect chars */ for (cur_pos = (cur_frag == start_frag) ? start_pos : 0; frag->str[cur_pos]; cur_pos++) { if (cur_frag >= start_frag && cur_pos >= start_pos && res_pos <= len) { result[res_pos++] = frag->str[cur_pos]; if (res_pos > len) { break; } } } } /* clean up and return */ result[res_pos] = 0;#if MIME_MAGIC_DEBUG ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, r, MODNAME ": rsl_strdup() %d chars: %s", res_pos - 1, result);#endif return result;}/* states for the state-machine algorithm in magic_rsl_to_request() */typedef enum { rsl_leading_space, rsl_type, rsl_subtype, rsl_separator, rsl_encoding} rsl_states;/* process the RSL and set the MIME info in the request record */static int magic_rsl_to_request(request_rec *r){ int cur_frag, /* current fragment number/counter */ cur_pos, /* current position within fragment */ type_frag, /* content type starting point: fragment */ type_pos, /* content type starting point: position */ type_len, /* content type length */ encoding_frag, /* content encoding starting point: fragment */ encoding_pos, /* content encoding starting point: position */ encoding_len; /* content encoding length */ magic_rsl *frag; /* list-traversal pointer */ rsl_states state; magic_req_rec *req_dat = (magic_req_rec *) ap_get_module_config(r->request_config, &mime_magic_module); /* check if we have a result */ if (!req_dat || !req_dat->head) { /* empty - no match, we defer to other Apache modules */ return DECLINED; } /* start searching for the type and encoding */ state = rsl_leading_space; type_frag = type_pos = type_len = 0; encoding_frag = encoding_pos = encoding_len = 0; for (frag = req_dat->head, cur_frag = 0; frag && frag->next; frag = frag->next, cur_frag++) { /* loop through the characters in the fragment */ for (cur_pos = 0; frag->str[cur_pos]; cur_pos++) { if (ap_isspace(frag->str[cur_pos])) { /* process whitespace actions for each state */ if (state == rsl_leading_space) { /* eat whitespace in this state */ continue; } else if (state == rsl_type) { /* whitespace: type has no slash! */ return DECLINED; } else if (state == rsl_subtype) { /* whitespace: end of MIME type */ state++; continue; } else if (state == rsl_separator) { /* eat whitespace in this state */ continue; } else if (state == rsl_encoding) { /* whitespace: end of MIME encoding */ /* we're done */ frag = req_dat->tail; break; } else { /* should not be possible */ /* abandon malfunctioning module */ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, MODNAME ": bad state %d (ws)", state); return DECLINED; } /* NOTREACHED */ } else if (state == rsl_type && frag->str[cur_pos] == '/') { /* copy the char and go to rsl_subtype state */ type_len++; state++; } else { /* process non-space actions for each state */ if (state == rsl_leading_space) { /* non-space: begin MIME type */ state++; type_frag = cur_frag; type_pos = cur_pos; type_len = 1; continue; } else if (state == rsl_type || state == rsl_subtype) { /* non-space: adds to type */ type_len++; continue; } else if (state == rsl_separator) { /* non-space: begin MIME encoding */ state++; encoding_frag = cur_frag; encoding_pos = cur_pos; encoding_len = 1; continue; } else if (state == rsl_encoding) { /* non-space: adds to encoding */ encoding_len++; continue; } else { /* should not be possible */ /* abandon malfunctioning module */ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, MODNAME ": bad state %d (ns)", state); return DECLINED; } /* NOTREACHED */ } /* NOTREACHED */ } } /* if we ended prior to state rsl_subtype, we had incomplete info */ if (state != rsl_subtype && state != rsl_separator && state != rsl_encoding) { /* defer to other modules */ return DECLINED; } /* save the info in the request record */ if (state == rsl_subtype || state == rsl_encoding || state == rsl_encoding) { char *tmp; tmp = rsl_strdup(r, type_frag, type_pos, type_len); /* XXX: this could be done at config time I'm sure... but I'm * confused by all this magic_rsl stuff. -djg */ ap_content_type_tolower(tmp); r->content_type = tmp; } if (state == rsl_encoding) { char *tmp; tmp = rsl_strdup(r, encoding_frag, encoding_pos, encoding_len); /* XXX: this could be done at config time I'm sure... but I'm * confused by all this magic_rsl stuff. -djg */ ap_str_tolower(tmp); r->content_encoding = tmp; } /* detect memory allocation errors */ if (!r->content_type || (state == rsl_encoding && !r->content_encoding)) { return HTTP_INTERNAL_SERVER_ERROR; } /* success! */ return OK;}/* * magic_process - process input file r Apache API request record * (formerly called "process" in file command, prefix added for clarity) Opens * the file and reads a fixed-size buffer to begin processing the contents. */static int magic_process(request_rec *r){ int fd = 0; unsigned char buf[HOWMANY + 1]; /* one extra for terminating '\0' */ int nbytes = 0; /* number of bytes read from a datafile */ int result; /* * first try judging the file based on its filesystem status */ switch ((result = fsmagic(r, r->filename))) { case DONE: magic_rsl_putchar(r, '\n'); return OK; case OK: break; default: /* fatal error, bail out */ return result; } if ((fd = ap_popenf(r->pool, r->filename, O_RDONLY, 0)) < 0) { /* We can't open it, but we were able to stat it. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, r, MODNAME ": can't read `%s'", r->filename); /* let some other handler decide what the problem is */ return DECLINED; } /* * try looking at the first HOWMANY bytes */ if ((nbytes = read(fd, (char *) buf, sizeof(buf) - 1)) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, MODNAME ": read failed: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } if (nbytes == 0) magic_rsl_puts(r, MIME_TEXT_UNKNOWN); else { buf[nbytes++] = '\0'; /* null-terminate it */ tryit(r, buf, nbytes); } (void) ap_pclosef(r->pool, fd); (void) magic_rsl_putchar(r, '\n'); return OK;}static void tryit(request_rec *r, unsigned char *buf, int nb){ /* * Try compression stuff */ if (zmagic(r, buf, nb) == 1) return; /* * try tests in /etc/magic (or surrogate magic file) */ if (softmagic(r, buf, nb) == 1) return; /* * try known keywords, check for ascii-ness too. */ if (ascmagic(r, buf, nb) == 1) return; /* * abandon hope, all ye who remain here */ magic_rsl_puts(r, MIME_BINARY_UNKNOWN);}#define EATAB {while (ap_isspace((unsigned char) *l)) ++l;}/* * apprentice - load configuration from the magic file r * API request record */static int apprentice(server_rec *s, pool *p){ FILE *f; char line[BUFSIZ + 1]; int errs = 0; int lineno;#if MIME_MAGIC_DEBUG int rule = 0; struct magic *m, *prevm;#endif char *fname; magic_server_config_rec *conf = (magic_server_config_rec *) ap_get_module_config(s->module_config, &mime_magic_module); fname = ap_server_root_relative(p, conf->magicfile); f = ap_pfopen(p, fname, "r"); if (f == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, s, MODNAME ": can't read magic file %s", fname); return -1; } /* set up the magic list (empty) */ conf->magic = conf->last = NULL; /* parse it */ for (lineno = 1; fgets(line, BUFSIZ, f) != NULL; lineno++) { int ws_offset; /* delete newline */ if (line[0]) { line[strlen(line) - 1] = '\0'; } /* skip leading whitespace */ ws_offset = 0; while (line[ws_offset] && ap_isspace(line[ws_offset])) { ws_offset++; } /* skip blank lines */ if (line[ws_offset] == 0) { continue; } /* comment, do not parse */ if (line[ws_offset] == '#') continue;#if MIME_MAGIC_DEBUG /* if we get here, we're going to use it so count it */ rule++;#endif /* parse it */ if (parse(s, p, line + ws_offset, lineno) != 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -