/* ** utility.c -- Apache layout module ** $Revision: 1.59 $ */ #include "mod_layout.h" LAYOUT_EXPORT(void) cleanup_mmap(void *data) { mmap_data *file = (mmap_data *)data; munmap(file->file, file->size); } LAYOUT_EXPORT(array_header *) layout_array_push_kind(pool *p,array_header *origin, array_header *new, int kind) { array_header *returnable = NULL; int x = 0; layout_string **new_layouts; layout_string **origin_layouts; new_layouts = (layout_string **) new->elts; origin_layouts = (layout_string **) origin->elts; if (!origin && !new) { return NULL; } else if (!origin) { return new; } else if (!new) { return origin; } /* Size of new plus some padding */ returnable = ap_make_array (p, new->nelts + 2 + origin->nelts, sizeof (layout_string *)); /* Copy in the origin pieces */ for (x = 0; x < origin->nelts; x++) { if (origin_layouts[x]->kind == kind) { *(layout_string **) ap_push_array (returnable) = (layout_string *) origin_layouts[x]; } } /* Copy in the new pieces */ for (x = 0; x < new->nelts; x++) { if (new_layouts[x]->kind == kind) { *(layout_string **) ap_push_array (returnable) = (layout_string *) new_layouts[x]; } } return returnable; } LAYOUT_EXPORT(int) check_type(layout_request *request) { #ifdef DEBUG printf("check_type: %s \n", request->type); #endif if(request->http == ORIGIN) { return 0; } unless(request->type) return 0; unless(strcmp(request->type, "text/plain")) return 1; unless(strcmp(request->type, "text/html")) return 1; return 0; } LAYOUT_EXPORT(layout_request *) create_layout_request(request_rec *r, layout_conf *cfg, const char *type) { layout_request *info = NULL; const char *content_length = NULL; info = ap_pcalloc(r->pool, sizeof(layout_request)); info->origin = cfg->display_origin; info->merge = cfg->merge; info->http_header = OFF; info->header = OFF; info->footer = OFF; if((content_length = ap_table_get(r->headers_in, "Content-Length"))) { info->length = (content_length ? atoi(content_length) : 0); } info->pid = getpid(); info->type = NULL; info->http = LAYOUT; info->type = type; #ifdef DEBUG //printf("IGNORES HTTP %d Header %d Footer %d\n", cfg->uris_ignore_http_header, cfg->uris_ignore_header, cfg->footer_enabled); #endif if(isOn(cfg->header_enabled)) { info->header = ON; if(cfg->uris_ignore_header) { if (table_find(cfg->uris_ignore_header, r->uri)) info->header = OFF; } } if(isOn(cfg->http_header_enabled)) { info->http_header = ON; if(cfg->uris_ignore_http_header) { if (table_find(cfg->uris_ignore_http_header, r->uri)) info->http_header = OFF; } } if(isOn(cfg->footer_enabled)) { info->footer = ON; if(cfg->uris_ignore_footer) { if (table_find(cfg->uris_ignore_footer, r->uri)) info->footer = OFF; } } return info; } LAYOUT_EXPORT(int) table_search(request_rec *r, const table * t, const char *string) { array_header *hdrs_arr; table_entry *elts; int i; if (string == NULL) return 0; if (t == NULL) return 0; hdrs_arr = ap_table_elts(t); elts = (table_entry *) hdrs_arr->elts; for (i = 0; i < hdrs_arr->nelts; ++i) { if(string_search(r, (char *)string, elts[i].key, 0, 0) == -1) return 0; } return 1; } LAYOUT_EXPORT(void) table_cat(table *src, table *dest, char *string) { array_header *hdrs_arr; table_entry *elts; int x; if (src == NULL) return; if (dest == NULL) return; hdrs_arr = ap_table_elts(src); elts = (table_entry *) hdrs_arr->elts; if(string) { for (x = 0; x < hdrs_arr->nelts; ++x) { unless(strcasecmp(string,elts[x].key)) ap_table_add(dest, elts[x].key, elts[x].val); } } else { for (x = 0; x < hdrs_arr->nelts; ++x) { ap_table_add(dest, elts[x].key, elts[x].val); } } } void table_list(char *string, const table * t) { array_header *hdrs_arr; table_entry *elts; int i; if (t == NULL) return; if (string == NULL) string = "table_list: "; hdrs_arr = ap_table_elts(t); elts = (table_entry *) hdrs_arr->elts; for (i = 0; i < hdrs_arr->nelts; ++i) { printf("%s:Key %s:%s:\n", string, elts[i].key, elts[i].val); } } LAYOUT_EXPORT(int) string_search(request_rec *r, char *string, const char *delim, int init_pos, int flag) { char *temp = NULL; char *sub_temp = NULL; char *lower = NULL; char *substring = NULL; int position = 0; int end = 0; int delim_size; int complete_position = 0; if(delim == NULL || string == NULL) return -1; /* length = strlen(string); */ delim_size = strlen(delim); temp = string + init_pos; complete_position = init_pos; while((position = ap_ind(temp, delim[0])) != -1) { sub_temp = temp + position; if((end = ap_ind(sub_temp, delim[delim_size - 1])) != -1) { substring = ap_pstrndup(r->pool, sub_temp , end + 1); lower = ap_pstrdup(r->pool, substring); ap_str_tolower(lower); unless(ap_fnmatch(delim, lower, FNM_CASE_BLIND)) { if(flag) { complete_position += position; } else { complete_position += position + end + 1; } return complete_position; } } else { return -1; } temp += end + 1; complete_position += end + 1; } return -1; } LAYOUT_EXPORT(int) parser_put(request_rec *r, layout_conf *cfg, layout_request *info, char *string, int init_pos) { char *temp = NULL; char *sub_temp = NULL; char *lower = NULL; char *substring = NULL; int length = 0; int end = 0; int x = 0; int j = 0; int match = 0; int complete_position = 0; int run = 0; layout_string **layouts; layouts = (layout_string **) cfg->layouts->elts; if(string == NULL) return -1; length = strlen(string); temp = string + init_pos; complete_position = init_pos; x = init_pos; while ( x < length ) { if( string[x] == '<') { sub_temp = string + x; if((end = ap_ind(sub_temp, '>')) != -1) { substring = ap_pstrndup(r->pool, sub_temp , end + 1); lower = ap_pstrdup(r->pool, substring); ap_str_tolower(lower); #ifdef DEBUG printf("MATCH: %s (%d)\n", lower, cfg->layouts->nelts); #endif for (j = 0; j < cfg->layouts->nelts; j++) { #ifdef DEBUG printf("\tWITH: %s\n", layouts[j]->pattern); #endif /* The next few lines should be reduced */ run = 1; if (layouts[j]->kind == HEADER && !info->header) { run = 0; } if (layouts[j]->kind == FOOTER && !info->footer) { run = 0; } if (run) { unless(ap_fnmatch(layouts[j]->pattern, lower, FNM_CASE_BLIND)) { if(layouts[j]->append == APPEND) { ap_rputs(substring,r); layout_print(r, cfg, info, j); if(isOn(cfg->notes)) update_info(r->notes, info); } else if(layouts[j]->append == PREPEND) { layout_print(r, cfg, info, j); if(isOn(cfg->notes)) update_info(r->notes, info); ap_rputs(substring, r); } else { /* We replace! */ layout_print(r, cfg, info, j); if(isOn(cfg->notes)) update_info(r->notes, info); } match++; } } } unless (match) { ap_rputs(substring, r); } match = 0; x += strlen(substring); } else { /* If we never match just write out the substring and keep going */ ap_rputc(string[x], r); x++; } } else { ap_rputc(string[x], r); x++; } } return -1; } LAYOUT_EXPORT(int) find_headers(request_rec *r, char *body) { int position = 0; char *temp = NULL; int end = 0; temp = body; if(body==NULL) { return -1; } while((position = ap_ind(temp, '\n')) != -1) { if(temp[position + 1] == '\n') { end = end + position + 1; return (end); } if(temp[position + 1] == '\r') { end += position + 2; return (end); } temp = temp + position + 1; end = end + position + 1; } return -1; } LAYOUT_EXPORT(int) get_fd_in(request_rec *r, char *filename) { int status = OK; int temp_fd = 0; if ((temp_fd = ap_popenf(r->pool, filename,O_RDONLY,S_IRWXU)) < 0) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "mod_layout:get_fd_in couldn't open a file descriptor for : %s", filename); return HTTP_INTERNAL_SERVER_ERROR; } unlink(filename); r->connection->client->fd_in = temp_fd; return status; } LAYOUT_EXPORT(int) layout_send_file(request_rec *r, char *filename) { int status = OK; int temp_fd = 0; mmap_data *map_data = NULL; struct stat sbuf; if ((temp_fd = ap_popenf(r->pool, filename,O_RDONLY,S_IRWXU)) < 0) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "mod_layout:layout_send_file couldn't open a file descriptor for : %s", filename); return HTTP_NOT_FOUND; } ap_note_cleanups_for_fd(r->pool, temp_fd); (void)fstat(temp_fd, &sbuf); map_data = ap_pcalloc (r->pool, sizeof (mmap_data)); map_data->size = sbuf.st_size; map_data->file = (char *)mmap(NULL, map_data->size, PROT_READ, MAP_PRIVATE, temp_fd, 0); ap_register_cleanup(r->pool, map_data, cleanup_mmap, ap_null_cleanup); ap_send_mmap(map_data->file, r, 0, map_data->size); ap_rflush(r); return status; } LAYOUT_EXPORT(int) get_fd_out(request_rec *r, char *filename, BUFF *buff) { int status = OK; int temp_fd = -1; if ((temp_fd = ap_popenf(r->pool, filename,O_RDWR|O_CREAT|O_TRUNC,S_IRWXU)) == -1) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "mod_layout couldn't create an out file descriptor at for : %s", filename); return HTTP_INTERNAL_SERVER_ERROR; } unlink(filename); buff->fd = temp_fd; return status; } /* Pretty simple method. Sucks up the POST into a file specified by filename. */ LAYOUT_EXPORT(int) read_content(request_rec *r, char *filename, long length) { int rc; char argsbuffer[HUGE_STRING_LEN]; int rsize, rpos=0; long len_read = 0; FILE *file; if (!(file = ap_pfopen(r->pool, filename, "w"))) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "mod_layout couldn't create a file for async : %s", filename); } if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK){ return rc; } if (ap_should_client_block(r)) { ap_hard_timeout("client_read", r); while((len_read = ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0 ){ ap_reset_timeout(r); if ((rpos + (int)len_read) > length) { rsize = length -rpos; } else { rsize = (int)len_read; } (void)fwrite(argsbuffer, (size_t)rsize, 1, file); rpos += rsize; } ap_kill_timeout(r); } ap_pfclose(r->pool, file); return rc; } int check_table(const char *a) { if (a == NULL) return 0; if('1' == a[0]) return 1; return 0; } /* This method is borrowed from alloc.c in the main apache distribution. */ LAYOUT_EXPORT(int) table_find(const table *t, const char *key) { array_header *hdrs_arr; table_entry *elts; int i; if (t == NULL) return 0; hdrs_arr = ap_table_elts(t); elts = (table_entry *) hdrs_arr->elts; if (key == NULL) return 0; for (i = 0; i < hdrs_arr->nelts; ++i) { if (!ap_fnmatch(elts[i].key, key, FNM_CASE_BLIND)) if(check_table(elts[i].val)) return 1; } return 0; } LAYOUT_EXPORT(void) update_info(const table *t, layout_request *info) { array_header *hdrs_arr; table_entry *elts; int i; if (t == NULL) return; hdrs_arr = ap_table_elts(t); elts = (table_entry *) hdrs_arr->elts; for (i = 0; i < hdrs_arr->nelts; ++i) { if (!ap_fnmatch(elts[i].key, "LAYOUT", FNM_CASE_BLIND)) { if (!ap_fnmatch(elts[i].val, "originoff", FNM_CASE_BLIND)) info->origin = OFF; else if (!ap_fnmatch(elts[i].val, "originon", FNM_CASE_BLIND)) info->origin = ON; else if (!ap_fnmatch(elts[i].val, "footeroff", FNM_CASE_BLIND)) info->footer = OFF; else if (!ap_fnmatch(elts[i].val, "footeron", FNM_CASE_BLIND)) info->footer = ON; else if (!ap_fnmatch(elts[i].val, "headeroff", FNM_CASE_BLIND)) info->header = OFF; else if (!ap_fnmatch(elts[i].val, "headeron", FNM_CASE_BLIND)) info->header = ON; else if (!ap_fnmatch(elts[i].val, "mergeoff", FNM_CASE_BLIND)) info->merge = OFF; else if (!ap_fnmatch(elts[i].val, "mergeon", FNM_CASE_BLIND)) info->merge = ON; } } } LAYOUT_EXPORT(int) is_ignored(request_rec *r, layout_conf *cfg, layout_request *info, char *body) { if(cfg->tag_ignore) { if(table_search(r, cfg->tag_ignore, body)){ info->header = OFF; info->footer = OFF; return 1; } } if(cfg->tag_ignore_footer) { if(table_search(r, cfg->tag_ignore_footer, body)){ info->footer = OFF; } } if(cfg->tag_ignore_header) { if(table_search(r, cfg->tag_ignore_header, body)){ info->header = OFF; } } return 0; } LAYOUT_EXPORT(void) layout_headers(request_rec *r, layout_conf *cfg, layout_request *info) { int status = LAYOUT; #ifdef old_code layout_string **current_header; #endif /* HTTP always overrule all headers */ if(info->http_header) { info->http = HTTP; return; } /* First, lets see if override is an issue */ #ifdef old_code if (table_find(cfg->override, info->type) || table_find(cfg->override_uri, r->uri)){ if(isOn(cfg->merge)) { status = ORIGIN; } else if (isOn(info->header)){ if(cfg->header) { current_header = (layout_string **) cfg->header->elts; if(current_header[0]->type == 0) { status = HEADER; } } } else { status = ORIGIN; } } #endif info->http = status; } LAYOUT_EXPORT(int) call_container(request_rec *r, const char *uri, layout_conf *cfg, layout_request *info, int assbackwards) { int status = OK; request_rec *subr; const char *temp = NULL; #ifdef LAYOUT_FILEOWNER_NAME struct passwd * uidpasswd = NULL; #endif if(isOn(cfg->async_post) && info->length) { reset_fd(r, info->length); subr = (request_rec *) ap_sub_req_method_uri((char *) r->method, uri, r); } else { subr = (request_rec *) ap_sub_req_lookup_uri(uri, r); ap_table_setn(subr->headers_in, "Content-Length", "0"); } ap_table_setn(subr->subprocess_env, "LAYOUT_SCRIPT_NAME", r->uri); ap_table_setn(subr->subprocess_env, "LAYOUT_PATH_INFO", r->path_info); ap_table_setn(subr->subprocess_env, "LAYOUT_QUERY_STRING", r->args); ap_table_setn(subr->subprocess_env, "LAYOUT_FILENAME", r->filename); ap_table_setn(subr->subprocess_env, "LAYOUT_LAST_MODIFIED", ap_ht_time(r->pool, r->finfo.st_mtime, cfg->time_format, 0)); #ifdef LAYOUT_FILEOWNER_NAME uidpasswd=getpwuid(r->finfo.st_uid); if (uidpasswd) ap_table_setn(subr->subprocess_env, "LAYOUT_FILEOWNER_NAME", uidpasswd->pw_name); #endif subr->args = r->args; subr->path_info = r->path_info; subr->assbackwards = assbackwards; temp = ap_table_get(r->headers_in, "Referer"); if(temp) ap_table_setn(subr->subprocess_env, "HTTP_REFERER", temp); status = ap_run_sub_req(subr); table_cat(subr->notes, r->notes, NULL); ap_destroy_sub_req(subr); return status; } LAYOUT_EXPORT(void) print_layout_headers(request_rec *r, layout_conf *cfg) { ap_rflush(r); r->content_type = "text/html"; ap_update_mtime(r, r->finfo.st_mtime); /* ap_set_last_modified(r);*/ /* ap_set_etag(r); */ /* Until I come up with a more intelligent way of doing this, everything is getting this header. */ if(isOn(cfg->cache_needed == ON)) { ap_table_setn(r->headers_out, "Cache-Control", "no-cache"); } ap_send_http_header(r); ap_rflush(r); } LAYOUT_EXPORT(char *) add_file(cmd_parms * cmd, layout_conf *cfg, const char *file) { FILE *file_ptr; char buf[HUGE_STRING_LEN]; char *content = NULL; if (!(file_ptr = ap_pfopen(cmd->temp_pool, file, "r"))) { ap_log_error(APLOG_MARK, APLOG_ERR, cmd->server, "Could not open layout file: %s", file); return NULL; } while (fgets(buf, HUGE_STRING_LEN, file_ptr)) { if(content) { content = ap_pstrcat(cmd->temp_pool, content, buf, NULL); } else { content = ap_pstrcat(cmd->temp_pool, buf, NULL); } } ap_pfclose(cmd->temp_pool, file_ptr); return content; } LAYOUT_EXPORT(void) reset_fd(request_rec *r, int length) { r->remaining = length; r->read_length = 0; r->read_chunked = 0; lseek(r->connection->client->fd_in, 0, SEEK_SET); } LAYOUT_EXPORT(void) layout_kind(request_rec *r, layout_conf *cfg, layout_request *info, int kind) { int x = 0; layout_string **layouts; layouts = (layout_string **) cfg->layouts->elts; for(x = 0; x < cfg->layouts->nelts; x++) { if (layouts[x]->kind == kind) { layout_print(r, cfg, info, x); } } }