/* * Get the file appropriate for a given error. */ static char *get_html_file (unsigned int errornum) { hashmap_iter result_iter; char errornbuf[ERRORNUM_BUFSIZE]; char *key; static char *val; assert (errornum >= 100 && errornum < 1000); if (!config.errorpages) return (config.errorpage_undef); snprintf (errornbuf, ERRORNUM_BUFSIZE, "%u", errornum); result_iter = hashmap_find (config.errorpages, errornbuf); if (hashmap_is_end (config.errorpages, result_iter)) return (config.errorpage_undef); if (hashmap_return_entry (config.errorpages, result_iter, &key, (void **) &val) < 0) return (config.errorpage_undef); return (val); }
/* * Look up the value for a variable. */ static char *lookup_variable (struct conn_s *connptr, const char *varname) { hashmap_iter result_iter; char *key; static char *data; result_iter = hashmap_find (connptr->error_variables, varname); if (hashmap_is_end (connptr->error_variables, result_iter)) return (NULL); if (hashmap_return_entry (connptr->error_variables, result_iter, &key, (void **) &data) < 0) return (NULL); return (data); }
/* * Loop through all the headers (including the response code) from the * server. */ static int process_server_headers(struct conn_s *connptr) { static char *skipheaders[] = { "keep-alive", "proxy-authenticate", "proxy-authorization", "proxy-connection", "transfer-encoding", }; char *response_line; hashmap_t hashofheaders; hashmap_iter iter; char *data, *header; ssize_t len; int i; int ret; /* FIXME: Remember to handle a "simple_req" type */ /* Get the response line from the remote server. */ retry: len = readline(connptr->server_fd, &response_line); if (len <= 0) return -1; /* * Strip the new line and character return from the string. */ if (chomp(response_line, len) == len) { /* * If the number of characters removed is the same as the * length then it was a blank line. Free the buffer and * try again (since we're looking for a request line.) */ safefree(response_line); goto retry; } hashofheaders = hashmap_create(HEADER_BUCKETS); if (!hashofheaders) { safefree(response_line); return -1; } /* * Get all the headers from the remote server in a big hash */ if (get_all_headers(connptr->server_fd, hashofheaders) < 0) { log_message(LOG_WARNING, "Could not retrieve all the headers from the remote server."); hashmap_delete(hashofheaders); safefree(response_line); indicate_http_error(connptr, 503, "Could not retrieve all the headers", "detail", PACKAGE " was unable to retrieve and process headers from the remote web server.", NULL); return -1; } /* Send the saved response line first */ ret = write_message(connptr->client_fd, "%s\r\n", response_line); safefree(response_line); if (ret < 0) goto ERROR_EXIT; /* * If there is a "Content-Length" header, retrieve the information * from it for later use. */ connptr->content_length.server = get_content_length(hashofheaders); /* * See if there is a connection header. If so, we need to to a bit of * processing. */ remove_connection_headers(hashofheaders); /* * Delete the headers listed in the skipheaders list */ for (i = 0; i != (sizeof(skipheaders) / sizeof(char *)); i++) { hashmap_remove(hashofheaders, skipheaders[i]); } /* Send, or add the Via header */ ret = write_via_header(connptr->client_fd, hashofheaders, connptr->protocol.major, connptr->protocol.minor); if (ret < 0) goto ERROR_EXIT; /* * All right, output all the remaining headers to the client. */ iter = hashmap_first(hashofheaders); if (iter >= 0) { for ( ; !hashmap_is_end(hashofheaders, iter); ++iter) { hashmap_return_entry(hashofheaders, iter, &data, (void **)&header); ret = write_message(connptr->client_fd, "%s: %s\r\n", data, header); if (ret < 0) goto ERROR_EXIT; } } hashmap_delete(hashofheaders); /* Write the final blank line to signify the end of the headers */ if (safe_write(connptr->client_fd, "\r\n", 2) < 0) return -1; return 0; ERROR_EXIT: hashmap_delete(hashofheaders); return -1; }
/* * Here we loop through all the headers the client is sending. If we * are running in anonymous mode, we will _only_ send the headers listed * (plus a few which are required for various methods). * - rjkaes */ static int process_client_headers(struct conn_s *connptr, hashmap_t hashofheaders) { static char *skipheaders[] = { "host", "keep-alive", "proxy-authenticate", "proxy-authorization", "proxy-connection", "te", "trailers", "transfer-encoding", "upgrade" }; int i; hashmap_iter iter; int ret = 0; char *data, *header; /* * Don't send headers if there's already an error, if the request was * a stats request, or if this was a CONNECT method (unless upstream * proxy is in use.) */ if (connptr->server_fd == -1 || connptr->show_stats || (connptr->connect_method && (connptr->upstream_proxy == NULL))) { log_message(LOG_INFO, "Not sending client headers to remote machine"); return 0; } /* * See if there is a "Content-Length" header. If so, again we need * to do a bit of processing. */ connptr->content_length.client = get_content_length(hashofheaders); /* * See if there is a "Connection" header. If so, we need to do a bit * of processing. :) */ remove_connection_headers(hashofheaders); /* * Delete the headers listed in the skipheaders list */ for (i = 0; i != (sizeof(skipheaders) / sizeof(char *)); i++) { hashmap_remove(hashofheaders, skipheaders[i]); } /* Send, or add the Via header */ ret = write_via_header(connptr->server_fd, hashofheaders, connptr->protocol.major, connptr->protocol.minor); if (ret < 0) { indicate_http_error(connptr, 503, "Could not send data to remote server", "detail", "A network error occurred while trying to write data to the remote web server.", NULL); goto PULL_CLIENT_DATA; } /* * Output all the remaining headers to the remote machine. */ iter = hashmap_first(hashofheaders); if (iter >= 0) { for ( ; !hashmap_is_end(hashofheaders, iter); ++iter) { hashmap_return_entry(hashofheaders, iter, &data, (void**)&header); if (!is_anonymous_enabled() || anonymous_search(data) > 0) { ret = write_message(connptr->server_fd, "%s: %s\r\n", data, header); if (ret < 0) { indicate_http_error(connptr, 503, "Could not send data to remote server", "detail", "A network error occurred while trying to write data to the remote web server.", NULL); goto PULL_CLIENT_DATA; } } } } #if defined(XTINYPROXY_ENABLE) if (config.my_domain) add_xtinyproxy_header(connptr); #endif /* Write the final "blank" line to signify the end of the headers */ if (safe_write(connptr->server_fd, "\r\n", 2) < 0) return -1; /* * Spin here pulling the data from the client. */ PULL_CLIENT_DATA: if (connptr->content_length.client > 0) return pull_client_data(connptr, connptr->content_length.client); else return ret; }