summaryrefslogtreecommitdiffhomepage
path: root/src/reqs.c
diff options
context:
space:
mode:
authorRobert James Kaes <rjkaes@users.sourceforge.net>2005-08-15 03:54:31 +0000
committerRobert James Kaes <rjkaes@users.sourceforge.net>2005-08-15 03:54:31 +0000
commitc0299e1868312e623c9b2ec6646cc7d1a5fe0f69 (patch)
tree83ea37f76e53ce502bbd813f7f93ed99d4df9efa /src/reqs.c
parent38f0b3a10354cd2297ae173a07ade3acd1aebd9a (diff)
* [Indent] Ran Source Through indent
I re-indented the source code using indent with the following options: indent -kr -bad -bap -nut -i8 -l80 -psl -sob -ss -ncs There are now _no_ tabs in the source files, and all indentation is eight spaces. Lines are 80 characters long, and the procedure type is on it's own line. Read the indent manual for more information about what each option means.
Diffstat (limited to 'src/reqs.c')
-rw-r--r--src/reqs.c2697
1 files changed, 1373 insertions, 1324 deletions
diff --git a/src/reqs.c b/src/reqs.c
index 5ff225b..e5e4061 100644
--- a/src/reqs.c
+++ b/src/reqs.c
@@ -1,4 +1,4 @@
-/* $Id: reqs.c,v 1.119 2005-07-12 17:39:44 rjkaes Exp $
+/* $Id: reqs.c,v 1.120 2005-08-15 03:54:31 rjkaes Exp $
*
* This is where all the work in tinyproxy is actually done. Incoming
* connections have a new child created for them. The child then
@@ -78,13 +78,13 @@ static vector_t ports_allowed_by_connect = NULL;
* This structure holds the information pulled from a URL request.
*/
struct request_s {
- char *method;
- char *protocol;
+ char *method;
+ char *protocol;
- char *host;
- uint16_t port;
+ char *host;
+ uint16_t port;
- char *path;
+ char *path;
};
/*
@@ -94,16 +94,18 @@ struct request_s {
void
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));
}
/*
@@ -115,23 +117,23 @@ add_connect_port_allowed(int port)
static int
check_allowed_connect_ports(int port)
{
- ssize_t i;
- int *data;
+ ssize_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;
+ 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);
+ 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 1;
+ }
- return 0;
+ return 0;
}
/*
@@ -142,35 +144,35 @@ check_allowed_connect_ports(int port)
static int
read_request_line(struct conn_s *connptr)
{
- ssize_t len;
+ 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;
+ 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;
}
/*
@@ -179,18 +181,18 @@ read_request_line(struct conn_s *connptr)
static void
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);
}
/*
@@ -198,9 +200,9 @@ free_request_struct(struct request_s *request)
* it off.
*/
static void
-strip_username_password(char* host)
+strip_username_password(char *host)
{
- char *p;
+ char *p;
assert(host);
assert(strlen(host) > 0);
@@ -213,7 +215,7 @@ strip_username_password(char* host)
* until the NUL to the beginning of the host buffer.
*/
p++;
- while (*p)
+ while (*p)
*host++ = *p++;
*host = '\0';
}
@@ -223,19 +225,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;
}
/*
@@ -245,42 +247,42 @@ strip_return_port(char* host)
static int
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;
}
/*
@@ -289,24 +291,24 @@ extract_http_url(const char *url, struct request_s *request)
static int
extract_ssl_url(const char *url, struct request_s *request)
{
- 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.");
-
- safefree(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.");
+
+ 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;
}
#ifdef TRANSPARENT_PROXY
@@ -316,21 +318,21 @@ extract_ssl_url(const char *url, struct request_s *request)
static int
build_url(char **url, const char *host, int port, const char *path)
{
- int len;
+ int len;
- assert(url != NULL);
- assert(host != NULL);
- assert(port > 0 && port < 32768);
- assert(path != NULL);
+ assert(url != NULL);
+ assert(host != NULL);
+ assert(port > 0 && port < 32768);
+ assert(path != NULL);
- len = strlen(host) + strlen(path) + 14;
- *url = safemalloc(len);
- if (*url == NULL)
- return -1;
+ len = strlen(host) + strlen(path) + 14;
+ *url = safemalloc(len);
+ if (*url == NULL)
+ return -1;
- return snprintf(*url, len, "http://%s:%d%s", host, port, path);
+ return snprintf(*url, len, "http://%s:%d%s", host, port, path);
}
-#endif /* TRANSPARENT_PROXY */
+#endif /* TRANSPARENT_PROXY */
#ifdef UPSTREAM_SUPPORT
/*
@@ -339,99 +341,107 @@ build_url(char **url, const char *host, int port, const char *path)
void
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;
}
/*
@@ -440,50 +450,50 @@ upstream_cleanup:
static struct upstream *
upstream_get(char *host)
{
- struct upstream *up = config.upstream_list;
+ struct upstream *up = config.upstream_list;
- in_addr_t my_ip = INADDR_NONE;
+ in_addr_t my_ip = INADDR_NONE;
- while (up) {
- if (up->domain) {
- if (strcasecmp(host, up->domain) == 0)
- break; /* exact match */
+ while (up) {
+ if (up->domain) {
+ if (strcasecmp(host, up->domain) == 0)
+ break; /* exact match */
- if (up->domain[0] == '.') {
- char *dot = strchr(host, '.');
+ if (up->domain[0] == '.') {
+ char *dot = strchr(host, '.');
- if (!dot && !up->domain[1])
- break; /* local host matches "." */
+ if (!dot && !up->domain[1])
+ break; /* local host matches "." */
- while (dot && strcasecmp(dot, up->domain))
- dot = strchr(dot+1, '.');
+ 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 (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 */
- }
+ if ((my_ip & up->mask) == up->ip)
+ break;
+ } else {
+ break; /* No domain or IP, default upstream */
+ }
- up = up->next;
- }
+ up = up->next;
+ }
- if (up && (!up->host || !up->port))
- up = NULL;
+ 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);
+ 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;
+ return up;
}
#endif
@@ -494,40 +504,47 @@ upstream_get(char *host)
void
reversepath_add(const char *path, const char *url)
{
- struct reversepath *reverse;
+ struct reversepath *reverse;
- if (url == NULL) {
- log_message(LOG_WARNING, "Illegal reverse proxy rule: missing url");
- return;
- }
+ if (url == NULL) {
+ log_message(LOG_WARNING,
+ "Illegal reverse proxy rule: missing url");
+ return;
+ }
- if (!strstr(url, "://")) {
- log_message(LOG_WARNING,
- "Skipping reverse proxy rule: '%s' is not a valid url", url);
- return;
- }
+ if (!strstr(url, "://")) {
+ log_message(LOG_WARNING,
+ "Skipping reverse proxy rule: '%s' is not a valid url",
+ url);
+ return;
+ }
- if (path && *path != '/') {
- log_message(LOG_WARNING,
- "Skipping reverse proxy rule: path '%s' doesn't start with a /", path);
- return;
- }
+ if (path && *path != '/') {
+ log_message(LOG_WARNING,
+ "Skipping reverse proxy rule: path '%s' doesn't start with a /",
+ path);
+ return;
+ }
- if (!(reverse = safemalloc(sizeof (struct reversepath)))) {
- log_message(LOG_ERR, "Unable to allocate memory in reversepath_add()");
- return;
- }
+ if (!(reverse = safemalloc(sizeof(struct reversepath)))) {
+ log_message(LOG_ERR,
+ "Unable to allocate memory in reversepath_add()");
+ return;
+ }
- if (!path) reverse->path = safestrdup("/");
- else reverse->path = safestrdup(path);
+ if (!path)
+ reverse->path = safestrdup("/");
+ else
+ reverse->path = safestrdup(path);
- reverse->url = safestrdup(url);
+ reverse->url = safestrdup(url);
- reverse->next = config.reversepath_list;
- config.reversepath_list = reverse;
+ reverse->next = config.reversepath_list;
+ config.reversepath_list = reverse;
- log_message(LOG_INFO,
- "Added reverse proxy rule: %s -> %s", reverse->path, reverse->url);
+ log_message(LOG_INFO,
+ "Added reverse proxy rule: %s -> %s", reverse->path,
+ reverse->url);
}
/*
@@ -536,16 +553,16 @@ reversepath_add(const char *path, const char *url)
static struct reversepath *
reversepath_get(char *url)
{
- struct reversepath *reverse = config.reversepath_list;
+ struct reversepath *reverse = config.reversepath_list;
- while (reverse) {
- if (strstr(url, reverse->path) == url)
- return reverse;
+ while (reverse) {
+ if (strstr(url, reverse->path) == url)
+ return reverse;
- reverse = reverse->next;
- }
+ reverse = reverse->next;
+ }
- return NULL;
+ return NULL;
}
#endif
@@ -555,20 +572,20 @@ reversepath_get(char *url)
static int
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);
}
/*
@@ -584,11 +601,10 @@ establish_http_connection(struct conn_s *connptr, struct request_s *request)
static inline int
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);
}
/*
@@ -598,42 +614,42 @@ send_ssl_response(struct conn_s *connptr)
static struct request_s *
process_request(struct conn_s *connptr, hashmap_t hashofheaders)
{
- char *url;
- struct request_s *request;
+ char *url;
+ struct request_s *request;
#ifdef REVERSE_SUPPORT
- char *rewrite_url = NULL;
- char *cookie = NULL;
- char *cookieval;
- struct reversepath *reverse;
+ char *rewrite_url = NULL;
+ char *cookie = NULL;
+ char *cookieval;
+ struct reversepath *reverse;
#endif
- int ret;
+ int ret;
- size_t request_len;
+ 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;
+ /* 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_len = strlen(connptr->request_line) + 1;
- request->method = safemalloc(request_len);
- url = safemalloc(request_len);
- request->protocol = safemalloc(request_len);
+ 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);
+ if (!request->method || !url || !request->protocol) {
+ safefree(url);
+ free_request_struct(request);
- return NULL;
- }
+ return NULL;
+ }
- ret = sscanf(connptr->request_line, "%[^ ] %[^ ] %[^ ]",
+ ret = sscanf(connptr->request_line, "%[^ ] %[^ ] %[^ ]",
request->method, url, request->protocol);
if (ret == 2 && !strcasecmp(request->method, "GET")) {
- request->protocol[0] = 0;
+ request->protocol[0] = 0;
/* Indicate that this is a HTTP/0.9 GET request */
connptr->protocol.major = 0;
@@ -654,271 +670,283 @@ process_request(struct conn_s *connptr, hashmap_t hashofheaders)
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;
- }
+ 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
- /*
- * Reverse proxy URL rewriting.
- */
- if (config.reversepath_list != NULL) {
- /* Reverse requests always start with a slash */
- if (*url == '/') {
- /* First try locating the reverse mapping by request url */
- reverse = reversepath_get(url);
- if (reverse) {
- rewrite_url = safemalloc(strlen(url) +
- strlen(reverse->url) + 1);
- strcpy(rewrite_url, reverse->url);
- strcat(rewrite_url, url + strlen(reverse->path));
- } else if (config.reversemagic &&
- hashmap_entry_by_key(hashofheaders, "cookie",
- (void **)&cookie) > 0) {
-
- /* No match - try the magical tracking cookie next */
- if ((cookieval = strstr(cookie, REVERSE_COOKIE "=")) &&
- (reverse = reversepath_get(cookieval +
- strlen(REVERSE_COOKIE) + 1))) {
-
- rewrite_url = safemalloc(strlen(url) +
- strlen(reverse->url) + 1);
- strcpy(rewrite_url, reverse->url);
- strcat(rewrite_url, url + 1);
-
- log_message(LOG_INFO,
- "Magical tracking cookie says: %s",
- reverse->path);
- }
- }
- }
-
- /* Forward proxy support off and no reverse path match found */
- if (config.reverseonly && !rewrite_url) {
- log_message(LOG_ERR, "Bad request");
- indicate_http_error(connptr, 400, "Bad Request",
- "detail", "Request has an invalid URL",
- "url", url,
- NULL);
-
- safefree(url);
- free_request_struct(request);
-
- return NULL;
- }
-
- log_message(LOG_CONN, "Rewriting URL: %s -> %s",
- url, rewrite_url);
-
- safefree(url);
- url = rewrite_url;
-
- /* Store reverse path so that the magical tracking cookie can be set */
- if (config.reversemagic) connptr->reversepath = safestrdup(reverse->path);
- }
+ /*
+ * Reverse proxy URL rewriting.
+ */
+ if (config.reversepath_list != NULL) {
+ /* Reverse requests always start with a slash */
+ if (*url == '/') {
+ /* First try locating the reverse mapping by request url */
+ reverse = reversepath_get(url);
+ if (reverse) {
+ rewrite_url = safemalloc(strlen(url) +
+ strlen(reverse->url) +
+ 1);
+ strcpy(rewrite_url, reverse->url);
+ strcat(rewrite_url,
+ url + strlen(reverse->path));
+ } else if (config.reversemagic
+ && hashmap_entry_by_key(hashofheaders,
+ "cookie",
+ (void **)&cookie) >
+ 0) {
+
+ /* No match - try the magical tracking cookie next */
+ if ((cookieval =
+ strstr(cookie, REVERSE_COOKIE "="))
+ && (reverse =
+ reversepath_get(cookieval +
+ strlen(REVERSE_COOKIE) +
+ 1))) {
+
+ rewrite_url = safemalloc(strlen(url) +
+ strlen
+ (reverse->
+ url) + 1);
+ strcpy(rewrite_url, reverse->url);
+ strcat(rewrite_url, url + 1);
+
+ log_message(LOG_INFO,
+ "Magical tracking cookie says: %s",
+ reverse->path);
+ }
+ }
+ }
+
+ /* Forward proxy support off and no reverse path match found */
+ if (config.reverseonly && !rewrite_url) {
+ log_message(LOG_ERR, "Bad request");
+ indicate_http_error(connptr, 400, "Bad Request",
+ "detail",
+ "Request has an invalid URL", "url",
+ url, NULL);
+
+ safefree(url);
+ free_request_struct(request);
+
+ return NULL;
+ }
+
+ log_message(LOG_CONN, "Rewriting URL: %s -> %s",
+ url, rewrite_url);
+
+ safefree(url);
+ url = rewrite_url;
+
+ /* Store reverse path so that the magical tracking cookie can be set */
+ if (config.reversemagic)
+ connptr->reversepath = safestrdup(reverse->path);
+ }
#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
- /*
- * This section of code is used for the transparent proxy
- * option. You will need to configure your firewall to
- * redirect all connections for HTTP traffic to tinyproxy
- * for this to work properly.
- *
- * This code was written by Petr Lampa <lampa@fit.vutbr.cz>
- */
- int length;
- char *data;
- length = hashmap_entry_by_key(hashofheaders, "host", (void **)&data);
- if (length <= 0) {
- struct sockaddr_in dest_addr;
-
- if (getsockname(connptr->client_fd, (struct sockaddr *)&dest_addr, &length) < 0) {
- log_message(LOG_ERR,
- "process_request: cannot get destination IP for %d",
- connptr->client_fd);
- indicate_http_error(connptr, 400, "Bad Request",
- "detail", "Unknown destination",
- "url", url,
- NULL);
- safefree(url);
- free_request_struct(request);
- return NULL;
- }
- request->host = safemalloc(17);
- strcpy(request->host, inet_ntoa(dest_addr.sin_addr));
- request->port = ntohs(dest_addr.sin_port);
- request->path = safemalloc(strlen(url) + 1);
- strcpy(request->path, url);
- safefree(url);
- build_url(&url, request->host, request->port, request->path);
- log_message(LOG_INFO,
- "process_request: trans IP %s %s for %d",
- request->method, url, connptr->client_fd);
- } else {
- request->host = safemalloc(length+1);
- if (sscanf(data, "%[^:]:%hu", request->host, &request->port) != 2) {
- strcpy(request->host, data);
- request->port = HTTP_PORT;
- }
- request->path = safemalloc(strlen(url) + 1);
- strcpy(request->path, url);
- safefree(url);
- build_url(&url, request->host, request->port, request->path);
- log_message(LOG_INFO,
- "process_request: trans Host %s %s for %d",
- request->method, url, connptr->client_fd);
- }
- if (config.ipAddr &&
- strcmp(request->host, config.ipAddr) == 0) {
- log_message(LOG_ERR,
- "process_request: destination IP is localhost %d",
- connptr->client_fd);
- indicate_http_error(connptr, 400, "Bad Request",
- "detail", "You tried to connect to the machine the proxy is running on",
- "url", url,
- NULL);
- safefree(url);
- free_request_struct(request);
- return NULL;
- }
+ /*
+ * This section of code is used for the transparent proxy
+ * option. You will need to configure your firewall to
+ * redirect all connections for HTTP traffic to tinyproxy
+ * for this to work properly.
+ *
+ * This code was written by Petr Lampa <lampa@fit.vutbr.cz>
+ */
+ int length;
+ char *data;
+
+ length =
+ hashmap_entry_by_key(hashofheaders, "host", (void **)&data);
+ if (length <= 0) {
+ struct sockaddr_in dest_addr;
+
+ if (getsockname
+ (connptr->client_fd, (struct sockaddr *)&dest_addr,
+ &length) < 0) {
+ log_message(LOG_ERR,
+ "process_request: cannot get destination IP for %d",
+ connptr->client_fd);
+ indicate_http_error(connptr, 400, "Bad Request",
+ "detail",
+ "Unknown destination",
+ "url", url, NULL);
+ safefree(url);
+ free_request_struct(request);
+ return NULL;
+ }
+ request->host = safemalloc(17);
+ strcpy(request->host, inet_ntoa(dest_addr.sin_addr));
+ request->port = ntohs(dest_addr.sin_port);
+ request->path = safemalloc(strlen(url) + 1);
+ strcpy(request->path, url);
+ safefree(url);
+ build_url(&url, request->host, request->port,
+ request->path);
+ log_message(LOG_INFO,
+ "process_request: trans IP %s %s for %d",
+ request->method, url, connptr->client_fd);
+ } else {
+ request->host = safemalloc(length + 1);
+ if (sscanf
+ (data, "%[^:]:%hu", request->host,
+ &request->port) != 2) {
+ strcpy(request->host, data);
+ request->port = HTTP_PORT;
+ }
+ request->path = safemalloc(strlen(url) + 1);
+ strcpy(request->path, url);
+ safefree(url);
+ build_url(&url, request->host, request->port,
+ request->path);
+ log_message(LOG_INFO,
+ "process_request: trans Host %s %s for %d",
+ request->method, url, connptr->client_fd);
+ }
+ if (config.ipAddr && strcmp(request->host, config.ipAddr) == 0) {
+ log_message(LOG_ERR,
+ "process_request: destination IP is localhost %d",
+ connptr->client_fd);
+ indicate_http_error(connptr, 400, "Bad Request",
+ "detail",
+ "You tried to connect to the machine the proxy is running on",
+ "url", url, NULL);
+ safefree(url);
+ free_request_struct(request);
+ return NULL;
+ }
#else
- log_message(LOG_ERR,
- "process_request: Unknown URL type on file descriptor %d",
- connptr->client_fd);
- indicate_http_error(connptr, 400, "Bad Request",
- "detail", "Unknown URL type",
- "url", url,
- NULL);
-
- safefree(url);
- free_request_struct(request);
-
- return NULL;
+ log_message(LOG_ERR,
+ "process_request: Unknown URL type on file descriptor %d",
+ connptr->client_fd);
+ indicate_http_error(connptr, 400, "Bad Request",
+ "detail", "Unknown URL type",
+ "url", url, NULL);
+
+ 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;
}
/*
@@ -930,48 +958,48 @@ process_request(struct conn_s *connptr, hashmap_t hashofheaders)
static int
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
@@ -984,11 +1012,10 @@ static inline int
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);
+ 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.)
@@ -998,23 +1025,23 @@ add_xtinyproxy_header(struct conn_s *connptr)
static inline int
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);
}
/*
@@ -1023,54 +1050,55 @@ add_header_to_connection(hashmap_t hashofheaders, char *header, size_t len)
static int
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);
+ }
}
/*
@@ -1080,49 +1108,51 @@ get_all_headers(int fd, hashmap_t hashofheaders)
static int
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;
}
/*
@@ -1132,15 +1162,17 @@ remove_connection_headers(hashmap_t hashofheaders)
static long
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;
}
/*
@@ -1152,40 +1184,38 @@ get_content_length(hashmap_t hashofheaders)
*/
static int
write_via_header(int fd, hashmap_t hashofheaders,
- unsigned int major, unsigned int minor)
+ 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;
}
/*
@@ -1202,107 +1232,108 @@ write_via_header(int fd, hashmap_t hashofheaders,
static int
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;
}
/*
@@ -1312,65 +1343,69 @@ process_client_headers(struct conn_s *connptr, hashmap_t hashofheaders)
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;
+ 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. */
+ /* 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;
- }
+ 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
@@ -1384,103 +1419,106 @@ process_server_headers(struct conn_s *connptr)
return 0;
}
-
- /* Send the saved response line first */
+ /* 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;
+ /*
+ * 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;
}
/*
@@ -1494,105 +1532,106 @@ process_server_headers(struct conn_s *connptr)
static void
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;
}
/*
@@ -1602,71 +1641,75 @@ static int
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
}
@@ -1682,112 +1725,117 @@ connect_to_upstream(struct conn_s *connptr, struct request_s *request)
void
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);
- }
+ 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);
+ free_request_struct(request);
if (process_client_headers(connptr, hashofheaders) < 0) {
update_stats(STAT_BADCONN);
@@ -1799,43 +1847,44 @@ handle_connection(int fd)
}
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;
+ 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;
}