summaryrefslogtreecommitdiff
path: root/src/reqs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/reqs.c')
-rw-r--r--src/reqs.c2745
1 files changed, 1429 insertions, 1316 deletions
diff --git a/src/reqs.c b/src/reqs.c
index a757c6f..ddf7e20 100644
--- a/src/reqs.c
+++ b/src/reqs.c
@@ -81,20 +81,22 @@ static vector_t ports_allowed_by_connect = NULL;
* it hasn't already by done.
*/
void
-add_connect_port_allowed(int port)
+add_connect_port_allowed (int port)
{
- if (!ports_allowed_by_connect) {
- ports_allowed_by_connect = vector_create();
- if (!ports_allowed_by_connect) {
- log_message(LOG_WARNING,
- "Could not create a list of allowed CONNECT ports");
- return;
- }
- }
-
- log_message(LOG_INFO, "Adding Port [%d] to the list allowed by CONNECT",
- port);
- vector_append(ports_allowed_by_connect, (void **)&port, sizeof(port));
+ if (!ports_allowed_by_connect)
+ {
+ ports_allowed_by_connect = vector_create ();
+ if (!ports_allowed_by_connect)
+ {
+ log_message (LOG_WARNING,
+ "Could not create a list of allowed CONNECT ports");
+ return;
+ }
+ }
+
+ log_message (LOG_INFO, "Adding Port [%d] to the list allowed by CONNECT",
+ port);
+ vector_append (ports_allowed_by_connect, (void **) &port, sizeof (port));
}
/*
@@ -104,25 +106,26 @@ add_connect_port_allowed(int port)
* 0 if denied
*/
static int
-check_allowed_connect_ports(int port)
+check_allowed_connect_ports (int port)
{
- size_t i;
- int *data;
-
- /*
- * A port list is REQUIRED for a CONNECT request to function
- * properly. This closes a potential security hole.
- */
- if (!ports_allowed_by_connect)
- return 0;
-
- for (i = 0; i != vector_length(ports_allowed_by_connect); ++i) {
- data = vector_getentry(ports_allowed_by_connect, i, NULL);
- if (data && *data == port)
- return 1;
- }
-
- return 0;
+ size_t i;
+ int *data;
+
+ /*
+ * A port list is REQUIRED for a CONNECT request to function
+ * properly. This closes a potential security hole.
+ */
+ if (!ports_allowed_by_connect)
+ return 0;
+
+ for (i = 0; i != vector_length (ports_allowed_by_connect); ++i)
+ {
+ data = vector_getentry (ports_allowed_by_connect, i, NULL);
+ if (data && *data == port)
+ return 1;
+ }
+
+ return 0;
}
/*
@@ -131,57 +134,59 @@ check_allowed_connect_ports(int port)
* be freed in another function.
*/
static int
-read_request_line(struct conn_s *connptr)
+read_request_line (struct conn_s *connptr)
{
- ssize_t len;
-
- retry:
- len = readline(connptr->client_fd, &connptr->request_line);
- if (len <= 0) {
- log_message(LOG_ERR,
- "read_request_line: Client (file descriptor: %d) closed socket before read.",
- connptr->client_fd);
-
- return -1;
- }
-
- /*
- * Strip the new line and carriage return from the string.
- */
- if (chomp(connptr->request_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(connptr->request_line);
- goto retry;
- }
-
- log_message(LOG_CONN, "Request (file descriptor %d): %s",
- connptr->client_fd, connptr->request_line);
-
- return 0;
+ ssize_t len;
+
+retry:
+ len = readline (connptr->client_fd, &connptr->request_line);
+ if (len <= 0)
+ {
+ log_message (LOG_ERR,
+ "read_request_line: Client (file descriptor: %d) closed socket before read.",
+ connptr->client_fd);
+
+ return -1;
+ }
+
+ /*
+ * Strip the new line and carriage return from the string.
+ */
+ if (chomp (connptr->request_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 (connptr->request_line);
+ goto retry;
+ }
+
+ log_message (LOG_CONN, "Request (file descriptor %d): %s",
+ connptr->client_fd, connptr->request_line);
+
+ return 0;
}
/*
* Free all the memory allocated in a request.
*/
static void
-free_request_struct(struct request_s *request)
+free_request_struct (struct request_s *request)
{
- if (!request)
- return;
+ if (!request)
+ return;
- safefree(request->method);
- safefree(request->protocol);
+ safefree (request->method);
+ safefree (request->protocol);
- if (request->host)
- safefree(request->host);
- if (request->path)
- safefree(request->path);
+ if (request->host)
+ safefree (request->host);
+ if (request->path)
+ safefree (request->path);
- safefree(request);
+ safefree (request);
}
/*
@@ -189,24 +194,24 @@ free_request_struct(struct request_s *request)
* it off.
*/
static void
-strip_username_password(char *host)
+strip_username_password (char *host)
{
- char *p;
-
- assert(host);
- assert(strlen(host) > 0);
-
- if ((p = strchr(host, '@')) == NULL)
- return;
-
- /*
- * Move the pointer past the "@" and then copy from that point
- * until the NUL to the beginning of the host buffer.
- */
- p++;
- while (*p)
- *host++ = *p++;
- *host = '\0';
+ char *p;
+
+ assert (host);
+ assert (strlen (host) > 0);
+
+ if ((p = strchr (host, '@')) == NULL)
+ return;
+
+ /*
+ * Move the pointer past the "@" and then copy from that point
+ * until the NUL to the beginning of the host buffer.
+ */
+ p++;
+ while (*p)
+ *host++ = *p++;
+ *host = '\0';
}
/*
@@ -214,19 +219,19 @@ strip_username_password(char *host)
* it off and set proper port variable i.e. for www.host.com:8001
*/
static int
-strip_return_port(char *host)
+strip_return_port (char *host)
{
- char *ptr1;
- int port;
+ char *ptr1;
+ int port;
- ptr1 = strchr(host, ':');
- if (ptr1 == NULL)
- return 0;
+ ptr1 = strchr (host, ':');
+ if (ptr1 == NULL)
+ return 0;
- *ptr1++ = '\0';
- if (sscanf(ptr1, "%d", &port) != 1) /* one conversion required */
- return 0;
- return port;
+ *ptr1++ = '\0';
+ if (sscanf (ptr1, "%d", &port) != 1) /* one conversion required */
+ return 0;
+ return port;
}
/*
@@ -234,70 +239,74 @@ strip_return_port(char *host)
* and FTP (proxied) URLs.
*/
static int
-extract_http_url(const char *url, struct request_s *request)
+extract_http_url (const char *url, struct request_s *request)
{
- char *p;
- int len;
- int port;
-
- /* Split the URL on the slash to separate host from path */
- p = strchr(url, '/');
- if (p != NULL) {
- len = p - url;
- request->host = safemalloc(len + 1);
- memcpy(request->host, url, len);
- request->host[len] = '\0';
- request->path = safestrdup(p);
- } else {
- request->host = safestrdup(url);
- request->path = safestrdup("/");
- }
-
- if (!request->host || !request->path)
- goto ERROR_EXIT;
-
- /* Remove the username/password if they're present */
- strip_username_password(request->host);
-
- /* Find a proper port in www.site.com:8001 URLs */
- port = strip_return_port(request->host);
- request->port = (port != 0) ? port : HTTP_PORT;
-
- return 0;
-
- ERROR_EXIT:
- if (request->host)
- safefree(request->host);
- if (request->path)
- safefree(request->path);
-
- return -1;
+ char *p;
+ int len;
+ int port;
+
+ /* Split the URL on the slash to separate host from path */
+ p = strchr (url, '/');
+ if (p != NULL)
+ {
+ len = p - url;
+ request->host = safemalloc (len + 1);
+ memcpy (request->host, url, len);
+ request->host[len] = '\0';
+ request->path = safestrdup (p);
+ }
+ else
+ {
+ request->host = safestrdup (url);
+ request->path = safestrdup ("/");
+ }
+
+ if (!request->host || !request->path)
+ goto ERROR_EXIT;
+
+ /* Remove the username/password if they're present */
+ strip_username_password (request->host);
+
+ /* Find a proper port in www.site.com:8001 URLs */
+ port = strip_return_port (request->host);
+ request->port = (port != 0) ? port : HTTP_PORT;
+
+ return 0;
+
+ERROR_EXIT:
+ if (request->host)
+ safefree (request->host);
+ if (request->path)
+ safefree (request->path);
+
+ return -1;
}
/*
* Extract the URL from a SSL connection.
*/
static int
-extract_ssl_url(const char *url, struct request_s *request)
+extract_ssl_url (const char *url, struct request_s *request)
{
- request->host = safemalloc(strlen(url) + 1);
- if (!request->host)
- return -1;
+ request->host = safemalloc (strlen (url) + 1);
+ if (!request->host)
+ return -1;
- if (sscanf(url, "%[^:]:%hu", request->host, &request->port) == 2) ;
- else if (sscanf(url, "%s", request->host) == 1)
- request->port = HTTP_PORT_SSL;
- else {
- log_message(LOG_ERR, "extract_ssl_url: Can't parse URL.");
+ if (sscanf (url, "%[^:]:%hu", request->host, &request->port) == 2);
+ else if (sscanf (url, "%s", request->host) == 1)
+ request->port = HTTP_PORT_SSL;
+ else
+ {
+ log_message (LOG_ERR, "extract_ssl_url: Can't parse URL.");
- safefree(request->host);
- return -1;
- }
+ safefree (request->host);
+ return -1;
+ }
- /* Remove the username/password if they're present */
- strip_username_password(request->host);
+ /* Remove the username/password if they're present */
+ strip_username_password (request->host);
- return 0;
+ return 0;
}
@@ -306,161 +315,183 @@ extract_ssl_url(const char *url, struct request_s *request)
* Add an entry to the upstream list
*/
void
-upstream_add(const char *host, int port, const char *domain)
+upstream_add (const char *host, int port, const char *domain)
{
- char *ptr;
- struct upstream *up = safemalloc(sizeof(struct upstream));
-
- if (!up) {
- log_message(LOG_ERR,
- "Unable to allocate memory in upstream_add()");
- return;
- }
-
- up->host = up->domain = NULL;
- up->ip = up->mask = 0;
-
- if (domain == NULL) {
- if (!host || host[0] == '\0' || port < 1) {
- log_message(LOG_WARNING,
- "Nonsense upstream rule: invalid host or port");
- goto upstream_cleanup;
- }
-
- up->host = safestrdup(host);
- up->port = port;
-
- log_message(LOG_INFO, "Added upstream %s:%d for [default]",
- host, port);
- } else if (host == NULL) {
- if (!domain || domain[0] == '\0') {
- log_message(LOG_WARNING,
- "Nonsense no-upstream rule: empty domain");
- goto upstream_cleanup;
- }
-
- ptr = strchr(domain, '/');
- if (ptr) {
- struct in_addr addrstruct;
-
- *ptr = '\0';
- if (inet_aton(domain, &addrstruct) != 0) {
- up->ip = ntohl(addrstruct.s_addr);
- *ptr++ = '/';
-
- if (strchr(ptr, '.')) {
- if (inet_aton(ptr, &addrstruct) != 0)
- up->mask =
- ntohl(addrstruct.s_addr);
- } else {
- up->mask =
- ~((1 << (32 - atoi(ptr))) - 1);
- }
- }
- } else {
- up->domain = safestrdup(domain);
- }
-
- log_message(LOG_INFO, "Added no-upstream for %s", domain);
- } else {
- if (!host || host[0] == '\0' || port < 1 || !domain
- || domain == '\0') {
- log_message(LOG_WARNING,
- "Nonsense upstream rule: invalid parameters");
- goto upstream_cleanup;
- }
-
- up->host = safestrdup(host);
- up->port = port;
- up->domain = safestrdup(domain);
-
- log_message(LOG_INFO, "Added upstream %s:%d for %s",
- host, port, domain);
- }
-
- if (!up->domain && !up->ip) { /* always add default to end */
- struct upstream *tmp = config.upstream_list;
-
- while (tmp) {
- if (!tmp->domain && !tmp->ip) {
- log_message(LOG_WARNING,
- "Duplicate default upstream");
- goto upstream_cleanup;
- }
-
- if (!tmp->next) {
- up->next = NULL;
- tmp->next = up;
- return;
- }
-
- tmp = tmp->next;
- }
- }
-
- up->next = config.upstream_list;
- config.upstream_list = up;
-
- return;
-
- upstream_cleanup:
- safefree(up->host);
- safefree(up->domain);
- safefree(up);
-
- return;
+ char *ptr;
+ struct upstream *up = safemalloc (sizeof (struct upstream));
+
+ if (!up)
+ {
+ log_message (LOG_ERR, "Unable to allocate memory in upstream_add()");
+ return;
+ }
+
+ up->host = up->domain = NULL;
+ up->ip = up->mask = 0;
+
+ if (domain == NULL)
+ {
+ if (!host || host[0] == '\0' || port < 1)
+ {
+ log_message (LOG_WARNING,
+ "Nonsense upstream rule: invalid host or port");
+ goto upstream_cleanup;
+ }
+
+ up->host = safestrdup (host);
+ up->port = port;
+
+ log_message (LOG_INFO, "Added upstream %s:%d for [default]",
+ host, port);
+ }
+ else if (host == NULL)
+ {
+ if (!domain || domain[0] == '\0')
+ {
+ log_message (LOG_WARNING,
+ "Nonsense no-upstream rule: empty domain");
+ goto upstream_cleanup;
+ }
+
+ ptr = strchr (domain, '/');
+ if (ptr)
+ {
+ struct in_addr addrstruct;
+
+ *ptr = '\0';
+ if (inet_aton (domain, &addrstruct) != 0)
+ {
+ up->ip = ntohl (addrstruct.s_addr);
+ *ptr++ = '/';
+
+ if (strchr (ptr, '.'))
+ {
+ if (inet_aton (ptr, &addrstruct) != 0)
+ up->mask = ntohl (addrstruct.s_addr);
+ }
+ else
+ {
+ up->mask = ~((1 << (32 - atoi (ptr))) - 1);
+ }
+ }
+ }
+ else
+ {
+ up->domain = safestrdup (domain);
+ }
+
+ log_message (LOG_INFO, "Added no-upstream for %s", domain);
+ }
+ else
+ {
+ if (!host || host[0] == '\0' || port < 1 || !domain || domain == '\0')
+ {
+ log_message (LOG_WARNING,
+ "Nonsense upstream rule: invalid parameters");
+ goto upstream_cleanup;
+ }
+
+ up->host = safestrdup (host);
+ up->port = port;
+ up->domain = safestrdup (domain);
+
+ log_message (LOG_INFO, "Added upstream %s:%d for %s",
+ host, port, domain);
+ }
+
+ if (!up->domain && !up->ip)
+ { /* always add default to end */
+ struct upstream *tmp = config.upstream_list;
+
+ while (tmp)
+ {
+ if (!tmp->domain && !tmp->ip)
+ {
+ log_message (LOG_WARNING, "Duplicate default upstream");
+ goto upstream_cleanup;
+ }
+
+ if (!tmp->next)
+ {
+ up->next = NULL;
+ tmp->next = up;
+ return;
+ }
+
+ tmp = tmp->next;
+ }
+ }
+
+ up->next = config.upstream_list;
+ config.upstream_list = up;
+
+ return;
+
+upstream_cleanup:
+ safefree (up->host);
+ safefree (up->domain);
+ safefree (up);
+
+ return;
}
/*
* Check if a host is in the upstream list
*/
static struct upstream *
-upstream_get(char *host)
+upstream_get (char *host)
{
- struct upstream *up = config.upstream_list;
-
- in_addr_t my_ip = INADDR_NONE;
-
- while (up) {
- if (up->domain) {
- if (strcasecmp(host, up->domain) == 0)
- break; /* exact match */
-
- if (up->domain[0] == '.') {
- char *dot = strchr(host, '.');
-
- if (!dot && !up->domain[1])
- break; /* local host matches "." */
-
- while (dot && strcasecmp(dot, up->domain))
- dot = strchr(dot + 1, '.');
-
- if (dot)
- break; /* subdomain match */
- }
- } else if (up->ip) {
- if (my_ip == INADDR_NONE)
- my_ip = ntohl(inet_addr(host));
-
- if ((my_ip & up->mask) == up->ip)
- break;
- } else {
- break; /* No domain or IP, default upstream */
- }
-
- up = up->next;
- }
-
- if (up && (!up->host || !up->port))
- up = NULL;
-
- if (up)
- log_message(LOG_INFO, "Found proxy %s:%d for %s",
- up->host, up->port, host);
- else
- log_message(LOG_INFO, "No proxy for %s", host);
-
- return up;
+ struct upstream *up = config.upstream_list;
+
+ in_addr_t my_ip = INADDR_NONE;
+
+ while (up)
+ {
+ if (up->domain)
+ {
+ if (strcasecmp (host, up->domain) == 0)
+ break; /* exact match */
+
+ if (up->domain[0] == '.')
+ {
+ char *dot = strchr (host, '.');
+
+ if (!dot && !up->domain[1])
+ break; /* local host matches "." */
+
+ while (dot && strcasecmp (dot, up->domain))
+ dot = strchr (dot + 1, '.');
+
+ if (dot)
+ break; /* subdomain match */
+ }
+ }
+ else if (up->ip)
+ {
+ if (my_ip == INADDR_NONE)
+ my_ip = ntohl (inet_addr (host));
+
+ if ((my_ip & up->mask) == up->ip)
+ break;
+ }
+ else
+ {
+ break; /* No domain or IP, default upstream */
+ }
+
+ up = up->next;
+ }
+
+ if (up && (!up->host || !up->port))
+ up = NULL;
+
+ if (up)
+ log_message (LOG_INFO, "Found proxy %s:%d for %s",
+ up->host, up->port, host);
+ else
+ log_message (LOG_INFO, "No proxy for %s", host);
+
+ return up;
}
#endif
@@ -468,22 +499,22 @@ upstream_get(char *host)
* Create a connection for HTTP connections.
*/
static int
-establish_http_connection(struct conn_s *connptr, struct request_s *request)
+establish_http_connection (struct conn_s *connptr, struct request_s *request)
{
- char portbuff[7];
-
- /* Build a port string if it's not a standard port */
- if (request->port != HTTP_PORT && request->port != HTTP_PORT_SSL)
- snprintf(portbuff, 7, ":%u", request->port);
- else
- portbuff[0] = '\0';
-
- return write_message(connptr->server_fd,
- "%s %s HTTP/1.0\r\n"
- "Host: %s%s\r\n"
- "Connection: close\r\n",
- request->method, request->path,
- request->host, portbuff);
+ char portbuff[7];
+
+ /* Build a port string if it's not a standard port */
+ if (request->port != HTTP_PORT && request->port != HTTP_PORT_SSL)
+ snprintf (portbuff, 7, ":%u", request->port);
+ else
+ portbuff[0] = '\0';
+
+ return write_message (connptr->server_fd,
+ "%s %s HTTP/1.0\r\n"
+ "Host: %s%s\r\n"
+ "Connection: close\r\n",
+ request->method, request->path,
+ request->host, portbuff);
}
/*
@@ -497,12 +528,12 @@ establish_http_connection(struct conn_s *connptr, struct request_s *request)
* connection.
*/
static inline int
-send_ssl_response(struct conn_s *connptr)
+send_ssl_response (struct conn_s *connptr)
{
- return write_message(connptr->client_fd,
- "%s\r\n"
- "%s\r\n"
- "\r\n", SSL_CONNECTION_RESPONSE, PROXY_AGENT);
+ return write_message (connptr->client_fd,
+ "%s\r\n"
+ "%s\r\n"
+ "\r\n", SSL_CONNECTION_RESPONSE, PROXY_AGENT);
}
/*
@@ -510,218 +541,239 @@ send_ssl_response(struct conn_s *connptr)
* build a new request line. Finally connect to the remote server.
*/
static struct request_s *
-process_request(struct conn_s *connptr, hashmap_t hashofheaders)
+process_request (struct conn_s *connptr, hashmap_t hashofheaders)
{
- char *url;
- struct request_s *request;
- int ret;
- size_t request_len;
-
- /* NULL out all the fields so frees don't cause segfaults. */
- request = safecalloc(1, sizeof(struct request_s));
- if (!request)
- return NULL;
-
- request_len = strlen(connptr->request_line) + 1;
-
- request->method = safemalloc(request_len);
- url = safemalloc(request_len);
- request->protocol = safemalloc(request_len);
-
- if (!request->method || !url || !request->protocol) {
- safefree(url);
- free_request_struct(request);
-
- return NULL;
- }
-
- ret = sscanf(connptr->request_line, "%[^ ] %[^ ] %[^ ]",
- request->method, url, request->protocol);
- if (ret == 2 && !strcasecmp(request->method, "GET")) {
- request->protocol[0] = 0;
-
- /* Indicate that this is a HTTP/0.9 GET request */
- connptr->protocol.major = 0;
- connptr->protocol.minor = 9;
- } else if (ret == 3 && !strncasecmp(request->protocol, "HTTP/", 5)) {
- /*
- * Break apart the protocol and update the connection
- * structure.
- */
- ret = sscanf(request->protocol + 5, "%u.%u",
- &connptr->protocol.major,
- &connptr->protocol.minor);
-
- /*
- * If the conversion doesn't succeed, drop down below and
- * send the error to the user.
- */
- if (ret != 2)
- goto BAD_REQUEST_ERROR;
- } else {
- BAD_REQUEST_ERROR:
- log_message(LOG_ERR,
- "process_request: Bad Request on file descriptor %d",
- connptr->client_fd);
- indicate_http_error(connptr, 400, "Bad Request",
- "detail", "Request has an invalid format",
- "url", url, NULL);
-
- safefree(url);
- free_request_struct(request);
-
- return NULL;
- }
-
- if (!url) {
- log_message(LOG_ERR,
- "process_request: Null URL on file descriptor %d",
- connptr->client_fd);
- indicate_http_error(connptr, 400, "Bad Request",
- "detail", "Request has an empty URL",
- "url", url, NULL);
-
- safefree(url);
- free_request_struct(request);
-
- return NULL;
- }
+ char *url;
+ struct request_s *request;
+ int ret;
+ size_t request_len;
+
+ /* NULL out all the fields so frees don't cause segfaults. */
+ request = safecalloc (1, sizeof (struct request_s));
+ if (!request)
+ return NULL;
+
+ request_len = strlen (connptr->request_line) + 1;
+
+ request->method = safemalloc (request_len);
+ url = safemalloc (request_len);
+ request->protocol = safemalloc (request_len);
+
+ if (!request->method || !url || !request->protocol)
+ {
+ safefree (url);
+ free_request_struct (request);
+
+ return NULL;
+ }
+
+ ret = sscanf (connptr->request_line, "%[^ ] %[^ ] %[^ ]",
+ request->method, url, request->protocol);
+ if (ret == 2 && !strcasecmp (request->method, "GET"))
+ {
+ request->protocol[0] = 0;
+
+ /* Indicate that this is a HTTP/0.9 GET request */
+ connptr->protocol.major = 0;
+ connptr->protocol.minor = 9;
+ }
+ else if (ret == 3 && !strncasecmp (request->protocol, "HTTP/", 5))
+ {
+ /*
+ * Break apart the protocol and update the connection
+ * structure.
+ */
+ ret = sscanf (request->protocol + 5, "%u.%u",
+ &connptr->protocol.major, &connptr->protocol.minor);
+
+ /*
+ * If the conversion doesn't succeed, drop down below and
+ * send the error to the user.
+ */
+ if (ret != 2)
+ goto BAD_REQUEST_ERROR;
+ }
+ else
+ {
+ BAD_REQUEST_ERROR:
+ log_message (LOG_ERR,
+ "process_request: Bad Request on file descriptor %d",
+ connptr->client_fd);
+ indicate_http_error (connptr, 400, "Bad Request",
+ "detail", "Request has an invalid format",
+ "url", url, NULL);
+
+ safefree (url);
+ free_request_struct (request);
+
+ return NULL;
+ }
+
+ if (!url)
+ {
+ log_message (LOG_ERR,
+ "process_request: Null URL on file descriptor %d",
+ connptr->client_fd);
+ indicate_http_error (connptr, 400, "Bad Request",
+ "detail", "Request has an empty URL",
+ "url", url, NULL);
+
+ safefree (url);
+ free_request_struct (request);
+
+ return NULL;
+ }
#ifdef REVERSE_SUPPORT
- if (config.reversepath_list != NULL) {
- /*
- * Rewrite the URL based on the reverse path. After calling
- * reverse_rewrite_url "url" can be freed since we either
- * have the newly rewritten URL, or something failed and
- * we'll be closing anyway.
- */
- char *reverse_url;
-
- reverse_url = reverse_rewrite_url(connptr, hashofheaders, url);
- safefree(url);
-
- if (!reverse_url) {
- free_request_struct(request);
- return NULL;
- } else {
- url = reverse_url;
- }
- }
+ if (config.reversepath_list != NULL)
+ {
+ /*
+ * Rewrite the URL based on the reverse path. After calling
+ * reverse_rewrite_url "url" can be freed since we either
+ * have the newly rewritten URL, or something failed and
+ * we'll be closing anyway.
+ */
+ char *reverse_url;
+
+ reverse_url = reverse_rewrite_url (connptr, hashofheaders, url);
+ safefree (url);
+
+ if (!reverse_url)
+ {
+ free_request_struct (request);
+ return NULL;
+ }
+ else
+ {
+ url = reverse_url;
+ }
+ }
#endif
- if (strncasecmp(url, "http://", 7) == 0
- || (UPSTREAM_CONFIGURED() && strncasecmp(url, "ftp://", 6) == 0)) {
- char *skipped_type = strstr(url, "//") + 2;
-
- if (extract_http_url(skipped_type, request) < 0) {
- indicate_http_error(connptr, 400, "Bad Request",
- "detail", "Could not parse URL",
- "url", url, NULL);
-
- safefree(url);
- free_request_struct(request);
-
- return NULL;
- }
- } else if (strcmp(request->method, "CONNECT") == 0) {
- if (extract_ssl_url(url, request) < 0) {
- indicate_http_error(connptr, 400, "Bad Request",
- "detail", "Could not parse URL",
- "url", url, NULL);
-
- safefree(url);
- free_request_struct(request);
-
- return NULL;
- }
-
- /* Verify that the port in the CONNECT method is allowed */
- if (!check_allowed_connect_ports(request->port)) {
- indicate_http_error(connptr, 403, "Access violation",
- "detail",
- "The CONNECT method not allowed "
- "with the port you tried to use.",
- "url", url, NULL);
- log_message(LOG_INFO,
- "Refused CONNECT method on port %d",
- request->port);
-
- safefree(url);
- free_request_struct(request);
-
- return NULL;
- }
-
- connptr->connect_method = TRUE;
- } else {
+ if (strncasecmp (url, "http://", 7) == 0
+ || (UPSTREAM_CONFIGURED () && strncasecmp (url, "ftp://", 6) == 0))
+ {
+ char *skipped_type = strstr (url, "//") + 2;
+
+ if (extract_http_url (skipped_type, request) < 0)
+ {
+ indicate_http_error (connptr, 400, "Bad Request",
+ "detail", "Could not parse URL",
+ "url", url, NULL);
+
+ safefree (url);
+ free_request_struct (request);
+
+ return NULL;
+ }
+ }
+ else if (strcmp (request->method, "CONNECT") == 0)
+ {
+ if (extract_ssl_url (url, request) < 0)
+ {
+ indicate_http_error (connptr, 400, "Bad Request",
+ "detail", "Could not parse URL",
+ "url", url, NULL);
+
+ safefree (url);
+ free_request_struct (request);
+
+ return NULL;
+ }
+
+ /* Verify that the port in the CONNECT method is allowed */
+ if (!check_allowed_connect_ports (request->port))
+ {
+ indicate_http_error (connptr, 403, "Access violation",
+ "detail",
+ "The CONNECT method not allowed "
+ "with the port you tried to use.",
+ "url", url, NULL);
+ log_message (LOG_INFO,
+ "Refused CONNECT method on port %d", request->port);
+
+ safefree (url);
+ free_request_struct (request);
+
+ return NULL;
+ }
+
+ connptr->connect_method = TRUE;
+ }
+ else
+ {
#ifdef TRANSPARENT_PROXY
- if (!do_transparent_proxy(connptr, hashofheaders, request, &config, url)) {
- safefree(url);
- free_request_struct(request);
- return NULL;
- }
+ if (!do_transparent_proxy
+ (connptr, hashofheaders, request, &config, url))
+ {
+ safefree (url);
+ free_request_struct (request);
+ return NULL;
+ }
#else
- indicate_http_error(connptr, 501, "Not Implemented",
- "detail", "Unknown method or unsupported protocol.",
- "url", url, NULL);
- log_message(LOG_INFO,
- "Unknown method (%s) or protocol (%s)",
- request->method, url);
- safefree(url);
- free_request_struct(request);
- return NULL;
-
+ indicate_http_error (connptr, 501, "Not Implemented",
+ "detail",
+ "Unknown method or unsupported protocol.", "url",
+ url, NULL);
+ log_message (LOG_INFO, "Unknown method (%s) or protocol (%s)",
+ request->method, url);
+ safefree (url);
+ free_request_struct (request);
+ return NULL;
+
#endif
- }
+ }
#ifdef FILTER_ENABLE
- /*
- * Filter restricted domains/urls
- */
- if (config.filter) {
- if (config.filter_url)
- ret = filter_url(url);
- else
- ret = filter_domain(request->host);
-
- if (ret) {
- update_stats(STAT_DENIED);
-
- if (config.filter_url)
- log_message(LOG_NOTICE,
- "Proxying refused on filtered url \"%s\"",
- url);
- else
- log_message(LOG_NOTICE,
- "Proxying refused on filtered domain \"%s\"",
- request->host);
-
- indicate_http_error(connptr, 403, "Filtered",
- "detail",
- "The request you made has been filtered",
- "url", url, NULL);
-
- safefree(url);
- free_request_struct(request);
-
- return NULL;
- }
- }
+ /*
+ * Filter restricted domains/urls
+ */
+ if (config.filter)
+ {
+ if (config.filter_url)
+ ret = filter_url (url);
+ else
+ ret = filter_domain (request->host);
+
+ if (ret)
+ {
+ update_stats (STAT_DENIED);
+
+ if (config.filter_url)
+ log_message (LOG_NOTICE,
+ "Proxying refused on filtered url \"%s\"", url);
+ else
+ log_message (LOG_NOTICE,
+ "Proxying refused on filtered domain \"%s\"",
+ request->host);
+
+ indicate_http_error (connptr, 403, "Filtered",
+ "detail",
+ "The request you made has been filtered",
+ "url", url, NULL);
+
+ safefree (url);
+ free_request_struct (request);
+
+ return NULL;
+ }
+ }
#endif
- safefree(url);
+ safefree (url);
- /*
- * Check to see if they're requesting the stat host
- */
- if (config.stathost && strcmp(config.stathost, request->host) == 0) {
- log_message(LOG_NOTICE, "Request for the stathost.");
- connptr->show_stats = TRUE;
+ /*
+ * Check to see if they're requesting the stat host
+ */
+ if (config.stathost && strcmp (config.stathost, request->host) == 0)
+ {
+ log_message (LOG_NOTICE, "Request for the stathost.");
+ connptr->show_stats = TRUE;
- free_request_struct(request);
- return NULL;
- }
+ free_request_struct (request);
+ return NULL;
+ }
- return request;
+ return request;
}
/*
@@ -731,50 +783,52 @@ process_request(struct conn_s *connptr, hashmap_t hashofheaders)
* - rjkaes
*/
static int
-pull_client_data(struct conn_s *connptr, long int length)
+pull_client_data (struct conn_s *connptr, long int length)
{
- char *buffer;
- ssize_t len;
-
- buffer = safemalloc(min(MAXBUFFSIZE, length));
- if (!buffer)
- return -1;
-
- do {
- len = safe_read(connptr->client_fd, buffer,
- min(MAXBUFFSIZE, length));
- if (len <= 0)
- goto ERROR_EXIT;
-
- if (!connptr->error_variables) {
- if (safe_write(connptr->server_fd, buffer, len) < 0)
- goto ERROR_EXIT;
- }
-
- length -= len;
- } while (length > 0);
-
- /*
- * BUG FIX: Internet Explorer will leave two bytes (carriage
- * return and line feed) at the end of a POST message. These
- * need to be eaten for tinyproxy to work correctly.
- */
- socket_nonblocking(connptr->client_fd);
- len = recv(connptr->client_fd, buffer, 2, MSG_PEEK);
- socket_blocking(connptr->client_fd);
-
- if (len < 0 && errno != EAGAIN)
- goto ERROR_EXIT;
-
- if (len == 2 && CHECK_CRLF(buffer, len))
- read(connptr->client_fd, buffer, 2);
-
- safefree(buffer);
- return 0;
-
- ERROR_EXIT:
- safefree(buffer);
- return -1;
+ char *buffer;
+ ssize_t len;
+
+ buffer = safemalloc (min (MAXBUFFSIZE, length));
+ if (!buffer)
+ return -1;
+
+ do
+ {
+ len = safe_read (connptr->client_fd, buffer, min (MAXBUFFSIZE, length));
+ if (len <= 0)
+ goto ERROR_EXIT;
+
+ if (!connptr->error_variables)
+ {
+ if (safe_write (connptr->server_fd, buffer, len) < 0)
+ goto ERROR_EXIT;
+ }
+
+ length -= len;
+ }
+ while (length > 0);
+
+ /*
+ * BUG FIX: Internet Explorer will leave two bytes (carriage
+ * return and line feed) at the end of a POST message. These
+ * need to be eaten for tinyproxy to work correctly.
+ */
+ socket_nonblocking (connptr->client_fd);
+ len = recv (connptr->client_fd, buffer, 2, MSG_PEEK);
+ socket_blocking (connptr->client_fd);
+
+ if (len < 0 && errno != EAGAIN)
+ goto ERROR_EXIT;
+
+ if (len == 2 && CHECK_CRLF (buffer, len))
+ read (connptr->client_fd, buffer, 2);
+
+ safefree (buffer);
+ return 0;
+
+ERROR_EXIT:
+ safefree (buffer);
+ return -1;
}
#ifdef XTINYPROXY_ENABLE
@@ -784,13 +838,13 @@ pull_client_data(struct conn_s *connptr, long int length)
* -rjkaes
*/
static inline int
-add_xtinyproxy_header(struct conn_s *connptr)
+add_xtinyproxy_header (struct conn_s *connptr)
{
- assert(connptr && connptr->server_fd >= 0);
- return write_message(connptr->server_fd,
- "X-Tinyproxy: %s\r\n", connptr->client_ip_addr);
+ assert (connptr && connptr->server_fd >= 0);
+ return write_message (connptr->server_fd,
+ "X-Tinyproxy: %s\r\n", connptr->client_ip_addr);
}
-#endif /* XTINYPROXY */
+#endif /* XTINYPROXY */
/*
* Take a complete header line and break it apart (into a key and the data.)
@@ -798,82 +852,86 @@ add_xtinyproxy_header(struct conn_s *connptr)
* can be retrieved and manipulated later.
*/
static inline int
-add_header_to_connection(hashmap_t hashofheaders, char *header, size_t len)
+add_header_to_connection (hashmap_t hashofheaders, char *header, size_t len)
{
- char *sep;
+ char *sep;
- /* Get rid of the new line and return at the end */
- len -= chomp(header, len);
+ /* Get rid of the new line and return at the end */
+ len -= chomp (header, len);
- sep = strchr(header, ':');
- if (!sep)
- return -1;
+ sep = strchr (header, ':');
+ if (!sep)
+ return -1;
- /* Blank out colons, spaces, and tabs. */
- while (*sep == ':' || *sep == ' ' || *sep == '\t')
- *sep++ = '\0';
+ /* Blank out colons, spaces, and tabs. */
+ while (*sep == ':' || *sep == ' ' || *sep == '\t')
+ *sep++ = '\0';
- /* Calculate the new length of just the data */
- len -= sep - header - 1;
+ /* Calculate the new length of just the data */
+ len -= sep - header - 1;
- return hashmap_insert(hashofheaders, header, sep, len);
+ return hashmap_insert (hashofheaders, header, sep, len);
}
/*
* Read all the headers from the stream
*/
static int
-get_all_headers(int fd, hashmap_t hashofheaders)
+get_all_headers (int fd, hashmap_t hashofheaders)
{
- char *header;
- ssize_t len;
- unsigned int double_cgi = FALSE; /* boolean */
-
- assert(fd >= 0);
- assert(hashofheaders != NULL);
-
- for (;;) {
- if ((len = readline(fd, &header)) <= 0) {
- safefree(header);
- return -1;
- }
-
- /*
- * If we received just a CR LF on a line, the headers are
- * finished.
- */
- if (CHECK_CRLF(header, len)) {
- safefree(header);
- return 0;
- }
-
- /*
- * BUG FIX: The following code detects a "Double CGI"
- * situation so that we can handle the nonconforming system.
- * This problem was found when accessing cgi.ebay.com, and it
- * turns out to be a wider spread problem as well.
- *
- * If "Double CGI" is in effect, duplicate headers are
- * ignored.
- *
- * FIXME: Might need to change this to a more robust check.
- */
- if (strncasecmp(header, "HTTP/", 5) == 0) {
- double_cgi = TRUE;
-
- safefree(header);
- continue;
- }
-
- if (!double_cgi
- && add_header_to_connection(hashofheaders, header,
- len) < 0) {
- safefree(header);
- return -1;
- }
-
- safefree(header);
- }
+ char *header;
+ ssize_t len;
+ unsigned int double_cgi = FALSE; /* boolean */
+
+ assert (fd >= 0);
+ assert (hashofheaders != NULL);
+
+ for (;;)
+ {
+ if ((len = readline (fd, &header)) <= 0)
+ {
+ safefree (header);
+ return -1;
+ }
+
+ /*
+ * If we received just a CR LF on a line, the headers are
+ * finished.
+ */
+ if (CHECK_CRLF (header, len))
+ {
+ safefree (header);
+ return 0;
+ }
+
+ /*
+ * BUG FIX: The following code detects a "Double CGI"
+ * situation so that we can handle the nonconforming system.
+ * This problem was found when accessing cgi.ebay.com, and it
+ * turns out to be a wider spread problem as well.
+ *
+ * If "Double CGI" is in effect, duplicate headers are
+ * ignored.
+ *
+ * FIXME: Might need to change this to a more robust check.
+ */
+ if (strncasecmp (header, "HTTP/", 5) == 0)
+ {
+ double_cgi = TRUE;
+
+ safefree (header);
+ continue;
+ }
+
+ if (!double_cgi
+ && add_header_to_connection (hashofheaders, header, len) < 0)
+ {
+ safefree (header);
+ return -1;
+ }
+
+ safefree (header);
+ }
}
/*
@@ -881,53 +939,53 @@ get_all_headers(int fd, hashmap_t hashofheaders)
* and Proxy-Connection headers.
*/
static int
-remove_connection_headers(hashmap_t hashofheaders)
+remove_connection_headers (hashmap_t hashofheaders)
{
- static char *headers[] = {
- "connection",
- "proxy-connection"
- };
-
- char *data;
- char *ptr;
- ssize_t len;
- int i;
-
- for (i = 0; i != (sizeof(headers) / sizeof(char *)); ++i) {
- /* Look for the connection header. If it's not found, return. */
- len =
- hashmap_entry_by_key(hashofheaders, headers[i],
- (void **)&data);
- if (len <= 0)
- return 0;
-
- /*
- * Go through the data line and replace any special characters
- * with a NULL.
- */
- ptr = data;
- while ((ptr = strpbrk(ptr, "()<>@,;:\\\"/[]?={} \t")))
- *ptr++ = '\0';
-
- /*
- * All the tokens are separated by NULLs. Now go through the
- * token and remove them from the hashofheaders.
- */
- ptr = data;
- while (ptr < data + len) {
- hashmap_remove(hashofheaders, ptr);
-
- /* Advance ptr to the next token */
- ptr += strlen(ptr) + 1;
- while (ptr < data + len && *ptr == '\0')
- ptr++;
- }
-
- /* Now remove the connection header it self. */
- hashmap_remove(hashofheaders, headers[i]);
- }
-
- return 0;
+ static char *headers[] = {
+ "connection",
+ "proxy-connection"
+ };
+
+ char *data;
+ char *ptr;
+ ssize_t len;
+ int i;
+
+ for (i = 0; i != (sizeof (headers) / sizeof (char *)); ++i)
+ {
+ /* Look for the connection header. If it's not found, return. */
+ len = hashmap_entry_by_key (hashofheaders, headers[i], (void **) &data);
+ if (len <= 0)
+ return 0;
+
+ /*
+ * Go through the data line and replace any special characters
+ * with a NULL.
+ */
+ ptr = data;
+ while ((ptr = strpbrk (ptr, "()<>@,;:\\\"/[]?={} \t")))
+ *ptr++ = '\0';
+
+ /*
+ * All the tokens are separated by NULLs. Now go through the
+ * token and remove them from the hashofheaders.
+ */
+ ptr = data;
+ while (ptr < data + len)
+ {
+ hashmap_remove (hashofheaders, ptr);
+
+ /* Advance ptr to the next token */
+ ptr += strlen (ptr) + 1;
+ while (ptr < data + len && *ptr == '\0')
+ ptr++;
+ }
+
+ /* Now remove the connection header it self. */
+ hashmap_remove (hashofheaders, headers[i]);
+ }
+
+ return 0;
}
/*
@@ -935,19 +993,18 @@ remove_connection_headers(hashmap_t hashofheaders)
* a negative number.
*/
static long
-get_content_length(hashmap_t hashofheaders)
+get_content_length (hashmap_t hashofheaders)
{
- ssize_t len;
- char *data;
- long content_length = -1;
+ ssize_t len;
+ char *data;
+ long content_length = -1;
- len =
- hashmap_entry_by_key(hashofheaders, "content-length",
- (void **)&data);
- if (len > 0)
- content_length = atol(data);
+ len =
+ hashmap_entry_by_key (hashofheaders, "content-length", (void **) &data);
+ if (len > 0)
+ content_length = atol (data);
- return content_length;
+ return content_length;
}
/*
@@ -958,39 +1015,44 @@ get_content_length(hashmap_t hashofheaders)
* purposes.
*/
static int
-write_via_header(int fd, hashmap_t hashofheaders,
- unsigned int major, unsigned int minor)
+write_via_header (int fd, hashmap_t hashofheaders,
+ unsigned int major, unsigned int minor)
{
- ssize_t len;
- char hostname[512];
- char *data;
- int ret;
-
- if (config.via_proxy_name) {
- strlcpy(hostname, config.via_proxy_name, sizeof(hostname));
- } else if (gethostname(hostname, sizeof(hostname)) < 0) {
- strcpy(hostname, "unknown");
- }
-
- /*
- * See if there is a "Via" header. If so, again we need to do a bit
- * of processing.
- */
- len = hashmap_entry_by_key(hashofheaders, "via", (void **)&data);
- if (len > 0) {
- ret = write_message(fd,
- "Via: %s, %hu.%hu %s (%s/%s)\r\n",
- data,
- major, minor, hostname, PACKAGE, VERSION);
-
- hashmap_remove(hashofheaders, "via");
- } else {
- ret = write_message(fd,
- "Via: %hu.%hu %s (%s/%s)\r\n",
- major, minor, hostname, PACKAGE, VERSION);
- }
-
- return ret;
+ ssize_t len;
+ char hostname[512];
+ char *data;
+ int ret;
+
+ if (config.via_proxy_name)
+ {
+ strlcpy (hostname, config.via_proxy_name, sizeof (hostname));
+ }
+ else if (gethostname (hostname, sizeof (hostname)) < 0)
+ {
+ strcpy (hostname, "unknown");
+ }
+
+ /*
+ * See if there is a "Via" header. If so, again we need to do a bit
+ * of processing.
+ */
+ len = hashmap_entry_by_key (hashofheaders, "via", (void **) &data);
+ if (len > 0)
+ {
+ ret = write_message (fd,
+ "Via: %s, %hu.%hu %s (%s/%s)\r\n",
+ data, major, minor, hostname, PACKAGE, VERSION);
+
+ hashmap_remove (hashofheaders, "via");
+ }
+ else
+ {
+ ret = write_message (fd,
+ "Via: %hu.%hu %s (%s/%s)\r\n",
+ major, minor, hostname, PACKAGE, VERSION);
+ }
+
+ return ret;
}
/*
@@ -1005,110 +1067,113 @@ write_via_header(int fd, hashmap_t hashofheaders,
* - rjkaes
*/
static int
-process_client_headers(struct conn_s *connptr, hashmap_t hashofheaders)
+process_client_headers (struct conn_s *connptr, hashmap_t hashofheaders)
{
- static char *skipheaders[] = {
- "host",
- "keep-alive",
- "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;
- }
- }
- }
- }
+ static char *skipheaders[] = {
+ "host",
+ "keep-alive",
+ "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);
+ 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;
+ /* 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;
}
/*
@@ -1116,184 +1181,192 @@ process_client_headers(struct conn_s *connptr, hashmap_t hashofheaders)
* server.
*/
static int
-process_server_headers(struct conn_s *connptr)
+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;
+ 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;
#ifdef REVERSE_SUPPORT
- struct reversepath *reverse = config.reversepath_list;
+ struct reversepath *reverse = config.reversepath_list;
#endif
- /* 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;
- }
-
- /*
- * At this point we've received the response line and all the
- * headers. However, if this is a simple HTTP/0.9 request we
- * CAN NOT send any of that information back to the client.
- * Instead we'll free all the memory and return.
- */
- if (connptr->protocol.major < 1) {
- hashmap_delete(hashofheaders);
- safefree(response_line);
- return 0;
- }
-
- /* 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;
+ /* 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;
+ }
+
+ /*
+ * At this point we've received the response line and all the
+ * headers. However, if this is a simple HTTP/0.9 request we
+ * CAN NOT send any of that information back to the client.
+ * Instead we'll free all the memory and return.
+ */
+ if (connptr->protocol.major < 1)
+ {
+ hashmap_delete (hashofheaders);
+ safefree (response_line);
+ return 0;
+ }
+
+ /* 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;
#ifdef REVERSE_SUPPORT
- /* Write tracking cookie for the magical reverse proxy path hack */
- if (config.reversemagic && connptr->reversepath) {
- ret = write_message(connptr->client_fd,
- "Set-Cookie: " REVERSE_COOKIE
- "=%s; path=/\r\n", connptr->reversepath);
- if (ret < 0)
- goto ERROR_EXIT;
- }
-
- /* Rewrite the HTTP redirect if needed */
- if (config.reversebaseurl &&
- hashmap_entry_by_key(hashofheaders, "location",
- (void **)&header) > 0) {
-
- /* Look for a matching entry in the reversepath list */
- while (reverse) {
- if (strncasecmp(header,
- reverse->url,
- (len = strlen(reverse->url))) == 0)
- break;
- reverse = reverse->next;
- }
-
- if (reverse) {
- ret =
- write_message(connptr->client_fd,
- "Location: %s%s%s\r\n",
- config.reversebaseurl,
- (reverse->path + 1), (header + len));
- if (ret < 0)
- goto ERROR_EXIT;
-
- log_message(LOG_INFO,
- "Rewriting HTTP redirect: %s -> %s%s%s",
- header, config.reversebaseurl,
- (reverse->path + 1), (header + len));
- hashmap_remove(hashofheaders, "location");
- }
- }
+ /* Write tracking cookie for the magical reverse proxy path hack */
+ if (config.reversemagic && connptr->reversepath)
+ {
+ ret = write_message (connptr->client_fd,
+ "Set-Cookie: " REVERSE_COOKIE
+ "=%s; path=/\r\n", connptr->reversepath);
+ if (ret < 0)
+ goto ERROR_EXIT;
+ }
+
+ /* Rewrite the HTTP redirect if needed */
+ if (config.reversebaseurl &&
+ hashmap_entry_by_key (hashofheaders, "location", (void **) &header) > 0)
+ {
+
+ /* Look for a matching entry in the reversepath list */
+ while (reverse)
+ {
+ if (strncasecmp (header,
+ reverse->url, (len = strlen (reverse->url))) == 0)
+ break;
+ reverse = reverse->next;
+ }
+
+ if (reverse)
+ {
+ ret =
+ write_message (connptr->client_fd,
+ "Location: %s%s%s\r\n",
+ config.reversebaseurl,
+ (reverse->path + 1), (header + len));
+ if (ret < 0)
+ goto ERROR_EXIT;
+
+ log_message (LOG_INFO,
+ "Rewriting HTTP redirect: %s -> %s%s%s",
+ header, config.reversebaseurl,
+ (reverse->path + 1), (header + len));
+ hashmap_remove (hashofheaders, "location");
+ }
+ }
#endif
- /*
- * 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;
+ /*
+ * 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;
}
/*
@@ -1305,186 +1378,204 @@ process_server_headers(struct conn_s *connptr)
* - rjkaes
*/
static void
-relay_connection(struct conn_s *connptr)
+relay_connection (struct conn_s *connptr)
{
- fd_set rset, wset;
- struct timeval tv;
- time_t last_access;
- int ret;
- double tdiff;
- int maxfd = max(connptr->client_fd, connptr->server_fd) + 1;
- ssize_t bytes_received;
-
- socket_nonblocking(connptr->client_fd);
- socket_nonblocking(connptr->server_fd);
-
- last_access = time(NULL);
-
- for (;;) {
- FD_ZERO(&rset);
- FD_ZERO(&wset);
-
- tv.tv_sec =
- config.idletimeout - difftime(time(NULL), last_access);
- tv.tv_usec = 0;
-
- if (buffer_size(connptr->sbuffer) > 0)
- FD_SET(connptr->client_fd, &wset);
- if (buffer_size(connptr->cbuffer) > 0)
- FD_SET(connptr->server_fd, &wset);
- if (buffer_size(connptr->sbuffer) < MAXBUFFSIZE)
- FD_SET(connptr->server_fd, &rset);
- if (buffer_size(connptr->cbuffer) < MAXBUFFSIZE)
- FD_SET(connptr->client_fd, &rset);
-
- ret = select(maxfd, &rset, &wset, NULL, &tv);
-
- if (ret == 0) {
- tdiff = difftime(time(NULL), last_access);
- if (tdiff > config.idletimeout) {
- log_message(LOG_INFO,
- "Idle Timeout (after select) as %g > %u.",
- tdiff, config.idletimeout);
- return;
- } else {
- continue;
- }
- } else if (ret < 0) {
- log_message(LOG_ERR,
- "relay_connection: select() error \"%s\". Closing connection (client_fd:%d, server_fd:%d)",
- strerror(errno), connptr->client_fd,
- connptr->server_fd);
- return;
- } else {
- /*
- * All right, something was actually selected so mark it.
- */
- last_access = time(NULL);
- }
-
- if (FD_ISSET(connptr->server_fd, &rset)) {
- bytes_received =
- read_buffer(connptr->server_fd, connptr->sbuffer);
- if (bytes_received < 0)
- break;
-
- connptr->content_length.server -= bytes_received;
- if (connptr->content_length.server == 0)
- break;
- }
- if (FD_ISSET(connptr->client_fd, &rset)
- && read_buffer(connptr->client_fd, connptr->cbuffer) < 0) {
- break;
- }
- if (FD_ISSET(connptr->server_fd, &wset)
- && write_buffer(connptr->server_fd, connptr->cbuffer) < 0) {
- break;
- }
- if (FD_ISSET(connptr->client_fd, &wset)
- && write_buffer(connptr->client_fd, connptr->sbuffer) < 0) {
- break;
- }
- }
-
- /*
- * Here the server has closed the connection... write the
- * remainder to the client and then exit.
- */
- socket_blocking(connptr->client_fd);
- while (buffer_size(connptr->sbuffer) > 0) {
- if (write_buffer(connptr->client_fd, connptr->sbuffer) < 0)
- break;
- }
- shutdown(connptr->client_fd, SHUT_WR);
-
- /*
- * Try to send any remaining data to the server if we can.
- */
- socket_blocking(connptr->server_fd);
- while (buffer_size(connptr->cbuffer) > 0) {
- if (write_buffer(connptr->server_fd, connptr->cbuffer) < 0)
- break;
- }
-
- return;
+ fd_set rset, wset;
+ struct timeval tv;
+ time_t last_access;
+ int ret;
+ double tdiff;
+ int maxfd = max (connptr->client_fd, connptr->server_fd) + 1;
+ ssize_t bytes_received;
+
+ socket_nonblocking (connptr->client_fd);
+ socket_nonblocking (connptr->server_fd);
+
+ last_access = time (NULL);
+
+ for (;;)
+ {
+ FD_ZERO (&rset);
+ FD_ZERO (&wset);
+
+ tv.tv_sec = config.idletimeout - difftime (time (NULL), last_access);
+ tv.tv_usec = 0;
+
+ if (buffer_size (connptr->sbuffer) > 0)
+ FD_SET (connptr->client_fd, &wset);
+ if (buffer_size (connptr->cbuffer) > 0)
+ FD_SET (connptr->server_fd, &wset);
+ if (buffer_size (connptr->sbuffer) < MAXBUFFSIZE)
+ FD_SET (connptr->server_fd, &rset);
+ if (buffer_size (connptr->cbuffer) < MAXBUFFSIZE)
+ FD_SET (connptr->client_fd, &rset);
+
+ ret = select (maxfd, &rset, &wset, NULL, &tv);
+
+ if (ret == 0)
+ {
+ tdiff = difftime (time (NULL), last_access);
+ if (tdiff > config.idletimeout)
+ {
+ log_message (LOG_INFO,
+ "Idle Timeout (after select) as %g > %u.",
+ tdiff, config.idletimeout);
+ return;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ else if (ret < 0)
+ {
+ log_message (LOG_ERR,
+ "relay_connection: select() error \"%s\". Closing connection (client_fd:%d, server_fd:%d)",
+ strerror (errno), connptr->client_fd,
+ connptr->server_fd);
+ return;
+ }
+ else
+ {
+ /*
+ * All right, something was actually selected so mark it.
+ */
+ last_access = time (NULL);
+ }
+
+ if (FD_ISSET (connptr->server_fd, &rset))
+ {
+ bytes_received = read_buffer (connptr->server_fd, connptr->sbuffer);
+ if (bytes_received < 0)
+ break;
+
+ connptr->content_length.server -= bytes_received;
+ if (connptr->content_length.server == 0)
+ break;
+ }
+ if (FD_ISSET (connptr->client_fd, &rset)
+ && read_buffer (connptr->client_fd, connptr->cbuffer) < 0)
+ {
+ break;
+ }
+ if (FD_ISSET (connptr->server_fd, &wset)
+ && write_buffer (connptr->server_fd, connptr->cbuffer) < 0)
+ {
+ break;
+ }
+ if (FD_ISSET (connptr->client_fd, &wset)
+ && write_buffer (connptr->client_fd, connptr->sbuffer) < 0)
+ {
+ break;
+ }
+ }
+
+ /*
+ * Here the server has closed the connection... write the
+ * remainder to the client and then exit.
+ */
+ socket_blocking (connptr->client_fd);
+ while (buffer_size (connptr->sbuffer) > 0)
+ {
+ if (write_buffer (connptr->client_fd, connptr->sbuffer) < 0)
+ break;
+ }
+ shutdown (connptr->client_fd, SHUT_WR);
+
+ /*
+ * Try to send any remaining data to the server if we can.
+ */
+ socket_blocking (connptr->server_fd);
+ while (buffer_size (connptr->cbuffer) > 0)
+ {
+ if (write_buffer (connptr->server_fd, connptr->cbuffer) < 0)
+ break;
+ }
+
+ return;
}
/*
* Establish a connection to the upstream proxy server.
*/
static int
-connect_to_upstream(struct conn_s *connptr, struct request_s *request)
+connect_to_upstream (struct conn_s *connptr, struct request_s *request)
{
#ifndef UPSTREAM_SUPPORT
- /*
- * This function does nothing if upstream support was not compiled
- * into tinyproxy.
- */
- return -1;
+ /*
+ * This function does nothing if upstream support was not compiled
+ * into tinyproxy.
+ */
+ return -1;
#else
- char *combined_string;
- int len;
-
- struct upstream *cur_upstream = connptr->upstream_proxy;
-
- if (!cur_upstream) {
- log_message(LOG_WARNING,
- "No upstream proxy defined for %s.", request->host);
- indicate_http_error(connptr, 404,
- "Unable to connect to upstream proxy.");
- return -1;
- }
-
- connptr->server_fd =
- opensock(cur_upstream->host, cur_upstream->port,
- connptr->server_ip_addr);
-
- if (connptr->server_fd < 0) {
- log_message(LOG_WARNING,
- "Could not connect to upstream proxy.");
- indicate_http_error(connptr, 404,
- "Unable to connect to upstream proxy",
- "detail",
- "A network error occurred while trying to connect to the upstream web proxy.",
- NULL);
- return -1;
- }
-
- log_message(LOG_CONN,
- "Established connection to upstream proxy \"%s\" using file descriptor %d.",
- cur_upstream->host, connptr->server_fd);
-
- /*
- * We need to re-write the "path" part of the request so that we
- * can reuse the establish_http_connection() function. It expects a
- * method and path.
- */
- if (connptr->connect_method) {
- len = strlen(request->host) + 7;
-
- combined_string = safemalloc(len);
- if (!combined_string) {
- return -1;
- }
-
- snprintf(combined_string, len, "%s:%d", request->host,
- request->port);
- } else {
- len = strlen(request->host) + strlen(request->path) + 14;
- combined_string = safemalloc(len);
- if (!combined_string) {
- return -1;
- }
-
- snprintf(combined_string, len, "http://%s:%d%s", request->host,
- request->port, request->path);
- }
-
- if (request->path)
- safefree(request->path);
- request->path = combined_string;
-
- return establish_http_connection(connptr, request);
+ char *combined_string;
+ int len;
+
+ struct upstream *cur_upstream = connptr->upstream_proxy;
+
+ if (!cur_upstream)
+ {
+ log_message (LOG_WARNING,
+ "No upstream proxy defined for %s.", request->host);
+ indicate_http_error (connptr, 404,
+ "Unable to connect to upstream proxy.");
+ return -1;
+ }
+
+ connptr->server_fd =
+ opensock (cur_upstream->host, cur_upstream->port,
+ connptr->server_ip_addr);
+
+ if (connptr->server_fd < 0)
+ {
+ log_message (LOG_WARNING, "Could not connect to upstream proxy.");
+ indicate_http_error (connptr, 404,
+ "Unable to connect to upstream proxy",
+ "detail",
+ "A network error occurred while trying to connect to the upstream web proxy.",
+ NULL);
+ return -1;
+ }
+
+ log_message (LOG_CONN,
+ "Established connection to upstream proxy \"%s\" using file descriptor %d.",
+ cur_upstream->host, connptr->server_fd);
+
+ /*
+ * We need to re-write the "path" part of the request so that we
+ * can reuse the establish_http_connection() function. It expects a
+ * method and path.
+ */
+ if (connptr->connect_method)
+ {
+ len = strlen (request->host) + 7;
+
+ combined_string = safemalloc (len);
+ if (!combined_string)
+ {
+ return -1;
+ }
+
+ snprintf (combined_string, len, "%s:%d", request->host, request->port);
+ }
+ else
+ {
+ len = strlen (request->host) + strlen (request->path) + 14;
+ combined_string = safemalloc (len);
+ if (!combined_string)
+ {
+ return -1;
+ }
+
+ snprintf (combined_string, len, "http://%s:%d%s", request->host,
+ request->port, request->path);
+ }
+
+ if (request->path)
+ safefree (request->path);
+ request->path = combined_string;
+
+ return establish_http_connection (connptr, request);
#endif
}
@@ -1498,168 +1589,190 @@ connect_to_upstream(struct conn_s *connptr, struct request_s *request)
* - rjkaes
*/
void
-handle_connection(int fd)
+handle_connection (int fd)
{
- struct conn_s *connptr;
- struct request_s *request = NULL;
- hashmap_t hashofheaders = NULL;
-
- char sock_ipaddr[IP_LENGTH];
- char peer_ipaddr[IP_LENGTH];
- char peer_string[HOSTNAME_LENGTH];
-
- getpeer_information(fd, peer_ipaddr, peer_string);
-
- if (config.bindsame)
- getsock_ip(fd, sock_ipaddr);
-
- log_message(LOG_CONN, config.bindsame ?
- "Connect (file descriptor %d): %s [%s] at [%s]" :
- "Connect (file descriptor %d): %s [%s]",
- fd, peer_string, peer_ipaddr, sock_ipaddr);
-
- connptr = initialize_conn(fd, peer_ipaddr, peer_string,
- config.bindsame ? sock_ipaddr : 0);
- if (!connptr) {
- close(fd);
- return;
- }
-
- if (check_acl(fd, peer_ipaddr, peer_string) <= 0) {
- update_stats(STAT_DENIED);
- indicate_http_error(connptr, 403, "Access denied",
- "detail",
- "The administrator of this proxy has not configured it to service requests from your host.",
- NULL);
- send_http_error_message(connptr);
- destroy_conn(connptr);
- return;
- }
-
- if (read_request_line(connptr) < 0) {
- update_stats(STAT_BADCONN);
- indicate_http_error(connptr, 408, "Timeout",
- "detail",
- "Server timeout waiting for the HTTP request from the client.",
- NULL);
- send_http_error_message(connptr);
- destroy_conn(connptr);
- return;
- }
-
- /*
- * The "hashofheaders" store the client's headers.
- */
- if (!(hashofheaders = hashmap_create(HEADER_BUCKETS))) {
- update_stats(STAT_BADCONN);
- indicate_http_error(connptr, 503, "Internal error",
- "detail",
- "An internal server error occurred while processing your request. Please contact the administrator.",
- NULL);
- send_http_error_message(connptr);
- destroy_conn(connptr);
- return;
- }
-
- /*
- * Get all the headers from the client in a big hash.
- */
- if (get_all_headers(connptr->client_fd, hashofheaders) < 0) {
- log_message(LOG_WARNING,
- "Could not retrieve all the headers from the client");
- hashmap_delete(hashofheaders);
- update_stats(STAT_BADCONN);
- destroy_conn(connptr);
- return;
- }
-
- request = process_request(connptr, hashofheaders);
- if (!request) {
- if (!connptr->error_variables && !connptr->show_stats) {
- update_stats(STAT_BADCONN);
- destroy_conn(connptr);
- hashmap_delete(hashofheaders);
- return;
- }
- goto send_error;
- }
-
- connptr->upstream_proxy = UPSTREAM_HOST(request->host);
- if (connptr->upstream_proxy != NULL) {
- if (connect_to_upstream(connptr, request) < 0) {
- goto send_error;
- }
- } else {
- connptr->server_fd = opensock(request->host, request->port,
- connptr->server_ip_addr);
- if (connptr->server_fd < 0) {
- indicate_http_error(connptr, 500, "Unable to connect",
- "detail",
- PACKAGE
- " was unable to connect to the remote web server.",
- "error", strerror(errno), NULL);
- goto send_error;
- }
-
- log_message(LOG_CONN,
- "Established connection to host \"%s\" using file descriptor %d.",
- request->host, connptr->server_fd);
-
- if (!connptr->connect_method)
- establish_http_connection(connptr, request);
- }
-
- send_error:
- free_request_struct(request);
-
- if (process_client_headers(connptr, hashofheaders) < 0) {
- update_stats(STAT_BADCONN);
- if (!connptr->error_variables) {
- hashmap_delete(hashofheaders);
- destroy_conn(connptr);
- return;
- }
- }
- hashmap_delete(hashofheaders);
-
- if (connptr->error_variables) {
- send_http_error_message(connptr);
- destroy_conn(connptr);
- return;
- } else if (connptr->show_stats) {
- showstats(connptr);
- destroy_conn(connptr);
- return;
- }
-
- if (!connptr->connect_method || (connptr->upstream_proxy != NULL)) {
- if (process_server_headers(connptr) < 0) {
- if (connptr->error_variables)
- send_http_error_message(connptr);
-
- update_stats(STAT_BADCONN);
- destroy_conn(connptr);
- return;
- }
- } else {
- if (send_ssl_response(connptr) < 0) {
- log_message(LOG_ERR,
- "handle_connection: Could not send SSL greeting to client.");
- update_stats(STAT_BADCONN);
- destroy_conn(connptr);
- return;
- }
- }
-
- relay_connection(connptr);
-
- log_message(LOG_INFO,
- "Closed connection between local client (fd:%d) and remote client (fd:%d)",
- connptr->client_fd, connptr->server_fd);
-
- /*
- * All done... close everything and go home... :)
- */
- destroy_conn(connptr);
- return;
+ struct conn_s *connptr;
+ struct request_s *request = NULL;
+ hashmap_t hashofheaders = NULL;
+
+ char sock_ipaddr[IP_LENGTH];
+ char peer_ipaddr[IP_LENGTH];
+ char peer_string[HOSTNAME_LENGTH];
+
+ getpeer_information (fd, peer_ipaddr, peer_string);
+
+ if (config.bindsame)
+ getsock_ip (fd, sock_ipaddr);
+
+ log_message (LOG_CONN, config.bindsame ?
+ "Connect (file descriptor %d): %s [%s] at [%s]" :
+ "Connect (file descriptor %d): %s [%s]",
+ fd, peer_string, peer_ipaddr, sock_ipaddr);
+
+ connptr = initialize_conn (fd, peer_ipaddr, peer_string,
+ config.bindsame ? sock_ipaddr : 0);
+ if (!connptr)
+ {
+ close (fd);
+ return;
+ }
+
+ if (check_acl (fd, peer_ipaddr, peer_string) <= 0)
+ {
+ update_stats (STAT_DENIED);
+ indicate_http_error (connptr, 403, "Access denied",
+ "detail",
+ "The administrator of this proxy has not configured it to service requests from your host.",
+ NULL);
+ send_http_error_message (connptr);
+ destroy_conn (connptr);
+ return;
+ }
+
+ if (read_request_line (connptr) < 0)
+ {
+ update_stats (STAT_BADCONN);
+ indicate_http_error (connptr, 408, "Timeout",
+ "detail",
+ "Server timeout waiting for the HTTP request from the client.",
+ NULL);
+ send_http_error_message (connptr);
+ destroy_conn (connptr);
+ return;
+ }
+
+ /*
+ * The "hashofheaders" store the client's headers.
+ */
+ if (!(hashofheaders = hashmap_create (HEADER_BUCKETS)))
+ {
+ update_stats (STAT_BADCONN);
+ indicate_http_error (connptr, 503, "Internal error",
+ "detail",
+ "An internal server error occurred while processing your request. Please contact the administrator.",
+ NULL);
+ send_http_error_message (connptr);
+ destroy_conn (connptr);
+ return;
+ }
+
+ /*
+ * Get all the headers from the client in a big hash.
+ */
+ if (get_all_headers (connptr->client_fd, hashofheaders) < 0)
+ {
+ log_message (LOG_WARNING,
+ "Could not retrieve all the headers from the client");
+ hashmap_delete (hashofheaders);
+ update_stats (STAT_BADCONN);
+ destroy_conn (connptr);
+ return;
+ }
+
+ request = process_request (connptr, hashofheaders);
+ if (!request)
+ {
+ if (!connptr->error_variables && !connptr->show_stats)
+ {
+ update_stats (STAT_BADCONN);
+ destroy_conn (connptr);
+ hashmap_delete (hashofheaders);
+ return;
+ }
+ goto send_error;
+ }
+
+ connptr->upstream_proxy = UPSTREAM_HOST (request->host);
+ if (connptr->upstream_proxy != NULL)
+ {
+ if (connect_to_upstream (connptr, request) < 0)
+ {
+ goto send_error;
+ }
+ }
+ else
+ {
+ connptr->server_fd = opensock (request->host, request->port,
+ connptr->server_ip_addr);
+ if (connptr->server_fd < 0)
+ {
+ indicate_http_error (connptr, 500, "Unable to connect",
+ "detail",
+ PACKAGE
+ " was unable to connect to the remote web server.",
+ "error", strerror (errno), NULL);
+ goto send_error;
+ }
+
+ log_message (LOG_CONN,
+ "Established connection to host \"%s\" using file descriptor %d.",
+ request->host, connptr->server_fd);
+
+ if (!connptr->connect_method)
+ establish_http_connection (connptr, request);
+ }
+
+send_error:
+ free_request_struct (request);
+
+ if (process_client_headers (connptr, hashofheaders) < 0)
+ {
+ update_stats (STAT_BADCONN);
+ if (!connptr->error_variables)
+ {
+ hashmap_delete (hashofheaders);
+ destroy_conn (connptr);
+ return;
+ }
+ }
+ hashmap_delete (hashofheaders);
+
+ if (connptr->error_variables)
+ {
+ send_http_error_message (connptr);
+ destroy_conn (connptr);
+ return;
+ }
+ else if (connptr->show_stats)
+ {
+ showstats (connptr);
+ destroy_conn (connptr);
+ return;
+ }
+
+ if (!connptr->connect_method || (connptr->upstream_proxy != NULL))
+ {
+ if (process_server_headers (connptr) < 0)
+ {
+ if (connptr->error_variables)
+ send_http_error_message (connptr);
+
+ update_stats (STAT_BADCONN);
+ destroy_conn (connptr);
+ return;
+ }
+ }
+ else
+ {
+ if (send_ssl_response (connptr) < 0)
+ {
+ log_message (LOG_ERR,
+ "handle_connection: Could not send SSL greeting to client.");
+ update_stats (STAT_BADCONN);
+ destroy_conn (connptr);
+ return;
+ }
+ }
+
+ relay_connection (connptr);
+
+ log_message (LOG_INFO,
+ "Closed connection between local client (fd:%d) and remote client (fd:%d)",
+ connptr->client_fd, connptr->server_fd);
+
+ /*
+ * All done... close everything and go home... :)
+ */
+ destroy_conn (connptr);
+ return;
}