summaryrefslogtreecommitdiff
path: root/src/reqs.c
diff options
context:
space:
mode:
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;
}