2002-04-25 00:47:19 +08:00
|
|
|
/* $Id: reqs.c,v 1.65 2002-04-24 16:47:19 rjkaes Exp $
|
2000-02-17 01:32:49 +08:00
|
|
|
*
|
|
|
|
* This is where all the work in tinyproxy is actually done. Incoming
|
2000-09-12 08:04:42 +08:00
|
|
|
* connections have a new thread created for them. The thread then
|
|
|
|
* processes the headers from the client, the response from the server,
|
|
|
|
* and then relays the bytes between the two.
|
2001-08-28 12:32:14 +08:00
|
|
|
* If TUNNEL_SUPPORT is enabled, then tinyproxy will actually work
|
2000-09-12 08:04:42 +08:00
|
|
|
* as a simple buffering TCP tunnel. Very cool! (Robert actually uses
|
2001-05-27 10:29:06 +08:00
|
|
|
* this feature for a buffering NNTP tunnel.)
|
2000-02-17 01:32:49 +08:00
|
|
|
*
|
2000-09-12 08:04:42 +08:00
|
|
|
* Copyright (C) 1998 Steven Young
|
2002-04-16 11:20:43 +08:00
|
|
|
* Copyright (C) 1999-2002 Robert James Kaes (rjkaes@flarenet.com)
|
2000-09-12 08:04:42 +08:00
|
|
|
* Copyright (C) 2000 Chris Lightfoot (chris@ex-parrot.com)
|
2000-02-17 01:32:49 +08:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
* later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "tinyproxy.h"
|
2000-09-12 08:04:42 +08:00
|
|
|
|
|
|
|
#include "acl.h"
|
|
|
|
#include "anonymous.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
#include "buffer.h"
|
2001-10-26 00:58:50 +08:00
|
|
|
#include "conns.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
#include "filter.h"
|
2002-04-08 05:35:59 +08:00
|
|
|
#include "hashmap.h"
|
2000-09-12 08:04:42 +08:00
|
|
|
#include "log.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
#include "regexp.h"
|
2000-09-12 08:04:42 +08:00
|
|
|
#include "reqs.h"
|
|
|
|
#include "sock.h"
|
|
|
|
#include "stats.h"
|
|
|
|
#include "utils.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
#define HTTP400ERROR "Unrecognizable request. Only HTTP is allowed."
|
|
|
|
#define HTTP500ERROR "Unable to connect to remote server."
|
|
|
|
#define HTTP503ERROR "Internal server error."
|
|
|
|
|
2001-12-18 03:10:56 +08:00
|
|
|
/*
|
|
|
|
* Maximum length of a HTTP line
|
|
|
|
*/
|
2001-12-19 13:13:40 +08:00
|
|
|
#define HTTP_LINE_LENGTH (MAXBUFFSIZE / 6)
|
2001-12-18 03:10:56 +08:00
|
|
|
|
2001-12-17 08:11:32 +08:00
|
|
|
/*
|
|
|
|
* Macro to help test if the Upstream proxy supported is compiled in and
|
|
|
|
* enabled.
|
|
|
|
*/
|
|
|
|
#ifdef UPSTREAM_SUPPORT
|
|
|
|
# define UPSTREAM_CONFIGURED() (config.upstream_name && config.upstream_port != -1)
|
|
|
|
#else
|
|
|
|
# define UPSTREAM_CONFIGURED() (0)
|
|
|
|
#endif
|
|
|
|
|
2001-12-19 13:13:40 +08:00
|
|
|
/*
|
|
|
|
* Macro to help test if tunnel support is compiled in, and is enabled.
|
|
|
|
*/
|
|
|
|
#ifdef TUNNEL_SUPPORT
|
|
|
|
# define TUNNEL_CONFIGURED() (config.tunnel_name && config.tunnel_port != -1)
|
|
|
|
#else
|
|
|
|
# define TUNNEL_CONFIGURED() (0)
|
|
|
|
#endif
|
|
|
|
|
2001-12-20 12:48:32 +08:00
|
|
|
/*
|
|
|
|
* Codify the test for the carriage return and new line characters.
|
|
|
|
*/
|
|
|
|
#define CHECK_CRLF(header, len) ((len == 1 && header[0] == '\n') || (len == 2 && header[0] == '\r' && header[1] == '\n'))
|
|
|
|
|
2002-04-13 01:00:42 +08:00
|
|
|
/*
|
|
|
|
* This is a global variable which stores which ports are allowed by
|
|
|
|
* the CONNECT method. It's a security thing.
|
|
|
|
*/
|
|
|
|
static vector_t ports_allowed_by_connect = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now, this routine adds a "port" to the list. It also creates the list if
|
|
|
|
* it hasn't already by done.
|
|
|
|
*/
|
|
|
|
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_insert(ports_allowed_by_connect, (void **)&port, sizeof(port));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This routine checks to see if a port is allowed in the CONNECT method.
|
|
|
|
*
|
|
|
|
* Returns: 1 if allowed
|
|
|
|
* 0 if denied
|
|
|
|
* negative upon error
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
check_allowed_connect_ports(int port)
|
|
|
|
{
|
|
|
|
ssize_t i;
|
|
|
|
ssize_t ret;
|
|
|
|
int *data;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the port list doesn't exist, allow everything. This might need
|
|
|
|
* to be changed in the future.
|
|
|
|
*/
|
|
|
|
if (!ports_allowed_by_connect)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
for (i = 0; i < vector_length(ports_allowed_by_connect); ++i) {
|
|
|
|
ret = vector_getentry(ports_allowed_by_connect, i, (void **)&data);
|
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (*data == port)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-02-17 01:32:49 +08:00
|
|
|
/*
|
2001-09-14 12:56:29 +08:00
|
|
|
* Read in the first line from the client (the request line for HTTP
|
|
|
|
* connections. The request line is allocated from the heap, but it must
|
|
|
|
* be freed in another function.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2002-04-08 05:35:59 +08:00
|
|
|
static int
|
2001-11-22 08:31:10 +08:00
|
|
|
read_request_line(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2002-04-15 12:14:03 +08:00
|
|
|
ssize_t len;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-12-17 08:11:32 +08:00
|
|
|
retry:
|
2002-04-08 05:35:59 +08:00
|
|
|
len = readline(connptr->client_fd, &connptr->request_line);
|
2001-08-27 05:11:55 +08:00
|
|
|
if (len <= 0) {
|
2001-11-22 08:31:10 +08:00
|
|
|
log_message(LOG_ERR,
|
|
|
|
"read_request_line: Client (file descriptor: %d) closed socket before read.",
|
|
|
|
connptr->client_fd);
|
2002-04-25 00:47:19 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-08-27 05:11:55 +08:00
|
|
|
/*
|
2001-09-14 12:56:29 +08:00
|
|
|
* Strip the new line and character return from the string.
|
2001-08-27 05:11:55 +08:00
|
|
|
*/
|
2002-04-08 05:35:59 +08:00
|
|
|
if (chomp(connptr->request_line, len) == len) {
|
2001-12-17 08:11:32 +08:00
|
|
|
/*
|
|
|
|
* 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.)
|
|
|
|
*/
|
2002-04-08 05:35:59 +08:00
|
|
|
safefree(connptr->request_line);
|
2001-12-17 08:11:32 +08:00
|
|
|
goto retry;
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
log_message(LOG_CONN, "Request (file descriptor %d): %s",
|
2002-04-08 05:35:59 +08:00
|
|
|
connptr->client_fd, connptr->request_line);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
return 0;
|
2001-09-14 12:56:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This structure holds the information pulled from a URL request.
|
|
|
|
*/
|
|
|
|
struct request_s {
|
2001-09-17 04:10:19 +08:00
|
|
|
char *method;
|
|
|
|
char *protocol;
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
char *host;
|
2002-04-08 05:35:59 +08:00
|
|
|
uint16_t port;
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
char *path;
|
|
|
|
};
|
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
static void
|
|
|
|
free_request_struct(struct request_s *request)
|
2001-09-17 04:10:19 +08:00
|
|
|
{
|
2001-10-23 00:08:29 +08:00
|
|
|
if (!request)
|
|
|
|
return;
|
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
safefree(request->method);
|
|
|
|
safefree(request->protocol);
|
|
|
|
|
|
|
|
safefree(request->host);
|
|
|
|
safefree(request->path);
|
|
|
|
|
|
|
|
safefree(request);
|
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
/*
|
|
|
|
* Pull the information out of the URL line.
|
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static int
|
|
|
|
extract_http_url(const char *url, struct request_s *request)
|
2001-09-14 12:56:29 +08:00
|
|
|
{
|
|
|
|
request->host = safemalloc(strlen(url) + 1);
|
|
|
|
request->path = safemalloc(strlen(url) + 1);
|
|
|
|
|
2002-04-16 11:20:43 +08:00
|
|
|
if (!request->host || !request->path)
|
|
|
|
goto ERROR_EXIT;
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
if (sscanf
|
2002-04-08 05:35:59 +08:00
|
|
|
(url, "http://%[^:/]:%hu%s", request->host, &request->port,
|
2001-11-22 08:31:10 +08:00
|
|
|
request->path) == 3) ;
|
2001-11-23 09:17:19 +08:00
|
|
|
else if (sscanf(url, "http://%[^/]%s", request->host, request->path) == 2)
|
2001-09-14 12:56:29 +08:00
|
|
|
request->port = 80;
|
2002-04-08 05:35:59 +08:00
|
|
|
else if (sscanf(url, "http://%[^:/]:%hu", request->host, &request->port)
|
2001-11-22 08:31:10 +08:00
|
|
|
== 2)
|
2001-09-14 12:56:29 +08:00
|
|
|
strcpy(request->path, "/");
|
|
|
|
else if (sscanf(url, "http://%[^/]", request->host) == 1) {
|
|
|
|
request->port = 80;
|
|
|
|
strcpy(request->path, "/");
|
|
|
|
} else {
|
2001-10-24 08:37:23 +08:00
|
|
|
log_message(LOG_ERR, "extract_http_url: Can't parse URL.");
|
2002-04-16 11:20:43 +08:00
|
|
|
goto ERROR_EXIT;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
return 0;
|
2002-04-16 11:20:43 +08:00
|
|
|
|
|
|
|
ERROR_EXIT:
|
2002-04-25 00:47:19 +08:00
|
|
|
if (request->host)
|
|
|
|
safefree(request->host);
|
|
|
|
if (request->path)
|
|
|
|
safefree(request->path);
|
2002-04-16 11:20:43 +08:00
|
|
|
|
|
|
|
return -1;
|
2001-09-14 12:56:29 +08:00
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
/*
|
|
|
|
* Extract the URL from a SSL connection.
|
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static int
|
|
|
|
extract_ssl_url(const char *url, struct request_s *request)
|
2001-09-14 12:56:29 +08:00
|
|
|
{
|
|
|
|
request->host = safemalloc(strlen(url) + 1);
|
2001-09-16 05:26:14 +08:00
|
|
|
if (!request->host)
|
2001-09-14 12:56:29 +08:00
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
if (sscanf(url, "%[^:]:%hu", request->host, &request->port) == 2) ;
|
2001-09-14 12:56:29 +08:00
|
|
|
else if (sscanf(url, "%s", request->host) == 1)
|
|
|
|
request->port = 443;
|
|
|
|
else {
|
2001-10-24 08:37:23 +08:00
|
|
|
log_message(LOG_ERR, "extract_ssl_url: Can't parse URL.");
|
2001-09-14 12:56:29 +08:00
|
|
|
|
|
|
|
safefree(request->host);
|
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2001-09-14 12:56:29 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-12-19 13:13:40 +08:00
|
|
|
/*
|
|
|
|
* Create a connection for HTTP connections.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
establish_http_connection(struct conn_s *connptr, struct request_s *request)
|
|
|
|
{
|
2002-04-16 11:20:43 +08:00
|
|
|
return write_message(connptr->server_fd,
|
|
|
|
"%s %s HTTP/1.0\r\n" \
|
|
|
|
"Host: %s\r\n" \
|
|
|
|
"Connection: close\r\n",
|
|
|
|
request->method, request->path, request->host);
|
2001-09-14 12:56:29 +08:00
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-16 05:26:14 +08:00
|
|
|
/*
|
|
|
|
* These two defines are for the SSL tunnelling.
|
|
|
|
*/
|
2002-04-16 11:20:43 +08:00
|
|
|
#define SSL_CONNECTION_RESPONSE "HTTP/1.0 200 Connection established"
|
|
|
|
#define PROXY_AGENT "Proxy-agent: " PACKAGE "/" VERSION
|
2001-09-16 05:26:14 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the appropriate response to the client to establish a SSL
|
|
|
|
* connection.
|
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static inline int
|
|
|
|
send_ssl_response(struct conn_s *connptr)
|
2001-09-16 05:26:14 +08:00
|
|
|
{
|
2002-04-16 11:20:43 +08:00
|
|
|
return write_message(connptr->client_fd,
|
|
|
|
"%s\r\n" \
|
|
|
|
"%s\r\n" \
|
|
|
|
"\r\n",
|
|
|
|
SSL_CONNECTION_RESPONSE, PROXY_AGENT);
|
2001-09-16 05:26:14 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
/*
|
|
|
|
* Break the request line apart and figure out where to connect and
|
|
|
|
* build a new request line. Finally connect to the remote server.
|
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static struct request_s *
|
2002-04-08 05:35:59 +08:00
|
|
|
process_request(struct conn_s *connptr)
|
2001-09-14 12:56:29 +08:00
|
|
|
{
|
|
|
|
char *url;
|
2001-09-17 04:10:19 +08:00
|
|
|
struct request_s *request;
|
2001-09-14 12:56:29 +08:00
|
|
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
size_t request_len;
|
|
|
|
|
|
|
|
/* NULL out all the fields so free's don't cause segfaults. */
|
2001-09-17 04:10:19 +08:00
|
|
|
request = safecalloc(1, sizeof(struct request_s));
|
|
|
|
if (!request)
|
|
|
|
return NULL;
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
request_len = strlen(connptr->request_line) + 1;
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
request->method = safemalloc(request_len);
|
2001-09-14 12:56:29 +08:00
|
|
|
url = safemalloc(request_len);
|
2001-09-17 04:10:19 +08:00
|
|
|
request->protocol = safemalloc(request_len);
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
if (!request->method || !url || !request->protocol) {
|
2001-09-14 12:56:29 +08:00
|
|
|
safefree(url);
|
2001-09-17 04:10:19 +08:00
|
|
|
free_request_struct(request);
|
|
|
|
|
|
|
|
return NULL;
|
2000-03-29 00:41:45 +08:00
|
|
|
}
|
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
ret =
|
2002-04-08 05:35:59 +08:00
|
|
|
sscanf(connptr->request_line, "%[^ ] %[^ ] %[^ ]",
|
|
|
|
request->method, url, request->protocol);
|
2001-09-14 12:56:29 +08:00
|
|
|
if (ret < 2) {
|
2001-11-22 08:31:10 +08:00
|
|
|
log_message(LOG_ERR,
|
|
|
|
"process_request: Bad Request on file descriptor %d",
|
|
|
|
connptr->client_fd);
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 400, "Bad Request. No request found.");
|
2001-09-14 12:56:29 +08:00
|
|
|
|
|
|
|
safefree(url);
|
2001-09-17 04:10:19 +08:00
|
|
|
free_request_struct(request);
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
return NULL;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2001-12-17 08:11:32 +08:00
|
|
|
/*
|
2002-04-16 11:20:43 +08:00
|
|
|
* FIXME: We need to add code for the simple HTTP/0.9 style GET
|
2001-12-17 08:11:32 +08:00
|
|
|
* request.
|
|
|
|
*/
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
if (!url) {
|
2001-11-22 08:31:10 +08:00
|
|
|
log_message(LOG_ERR,
|
|
|
|
"process_request: Null URL on file descriptor %d",
|
|
|
|
connptr->client_fd);
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 400, "Bad Request. Null URL.");
|
2001-09-14 12:56:29 +08:00
|
|
|
|
|
|
|
safefree(url);
|
2001-09-17 04:10:19 +08:00
|
|
|
free_request_struct(request);
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
return NULL;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
if (strncasecmp(url, "http://", 7) == 0) {
|
|
|
|
/* Make sure the first four characters are lowercase */
|
|
|
|
memcpy(url, "http", 4);
|
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
if (extract_http_url(url, request) < 0) {
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 400,
|
2001-11-22 08:31:10 +08:00
|
|
|
"Bad Request. Could not parse URL.");
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
safefree(url);
|
2001-09-17 04:10:19 +08:00
|
|
|
free_request_struct(request);
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
return NULL;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2001-09-17 04:10:19 +08:00
|
|
|
} else if (strcmp(request->method, "CONNECT") == 0) {
|
|
|
|
if (extract_ssl_url(url, request) < 0) {
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 400,
|
2001-11-22 08:31:10 +08:00
|
|
|
"Bad Request. Could not parse URL.");
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
safefree(url);
|
2001-09-17 04:10:19 +08:00
|
|
|
free_request_struct(request);
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
return NULL;
|
2000-04-01 06:55:22 +08:00
|
|
|
}
|
2002-04-13 01:00:42 +08:00
|
|
|
|
|
|
|
/* Verify that the port in the CONNECT method is allowed */
|
|
|
|
if (check_allowed_connect_ports(request->port) <= 0) {
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 403,
|
2002-04-13 01:00:42 +08:00
|
|
|
"CONNECT method not allowed with selected port.");
|
|
|
|
log_message(LOG_INFO, "Refused CONNECT method on port %d",
|
|
|
|
request->port);
|
|
|
|
|
|
|
|
safefree(url);
|
|
|
|
free_request_struct(request);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2001-12-17 08:11:32 +08:00
|
|
|
|
|
|
|
connptr->connect_method = TRUE;
|
2000-04-01 06:55:22 +08:00
|
|
|
} else {
|
2001-11-22 08:31:10 +08:00
|
|
|
log_message(LOG_ERR,
|
|
|
|
"process_request: Unknown URL type on file descriptor %d",
|
|
|
|
connptr->client_fd);
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 400, "Bad Request. Unknown URL type.");
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
safefree(url);
|
2001-09-17 04:10:19 +08:00
|
|
|
free_request_struct(request);
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
return NULL;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
safefree(url);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
#ifdef FILTER_ENABLE
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
2001-09-14 12:56:29 +08:00
|
|
|
* Filter restricted domains
|
2000-09-12 08:04:42 +08:00
|
|
|
*/
|
2001-09-14 12:56:29 +08:00
|
|
|
if (config.filter) {
|
2001-09-17 04:10:19 +08:00
|
|
|
if (filter_url(request->host)) {
|
|
|
|
update_stats(STAT_DENIED);
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
log_message(LOG_NOTICE,
|
|
|
|
"Proxying refused on filtered domain \"%s\"",
|
|
|
|
request->host);
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 404,
|
2001-11-22 08:31:10 +08:00
|
|
|
"Connection to filtered domain is now allowed.");
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
free_request_struct(request);
|
2001-09-14 12:56:29 +08:00
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
return NULL;
|
2001-09-14 12:56:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-16 05:26:14 +08:00
|
|
|
/*
|
|
|
|
* Check to see if they're requesting the stat host
|
|
|
|
*/
|
2001-09-17 04:10:19 +08:00
|
|
|
if (config.stathost && strcmp(config.stathost, request->host) == 0) {
|
2001-10-24 08:37:23 +08:00
|
|
|
log_message(LOG_NOTICE, "Request for the stathost.");
|
2002-04-19 05:43:53 +08:00
|
|
|
connptr->show_stats = TRUE;
|
2001-09-16 05:26:14 +08:00
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
free_request_struct(request);
|
|
|
|
return NULL;
|
2001-09-14 12:56:29 +08:00
|
|
|
}
|
|
|
|
|
2001-11-21 08:59:33 +08:00
|
|
|
/*
|
|
|
|
* Break apart the protocol and update the connection structure.
|
|
|
|
*/
|
|
|
|
if (strncasecmp(request->protocol, "http", 4) == 0) {
|
|
|
|
memcpy(request->protocol, "HTTP", 4);
|
2001-12-17 08:11:32 +08:00
|
|
|
sscanf(request->protocol, "HTTP/%u.%u",
|
2001-11-22 08:31:10 +08:00
|
|
|
&connptr->protocol.major, &connptr->protocol.minor);
|
2001-11-21 08:59:33 +08:00
|
|
|
}
|
|
|
|
|
2001-09-17 04:10:19 +08:00
|
|
|
return request;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-09-12 08:04:42 +08:00
|
|
|
* pull_client_data is used to pull across any client data (like in a
|
|
|
|
* POST) which needs to be handled before an error can be reported, or
|
|
|
|
* server headers can be processed.
|
|
|
|
* - rjkaes
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static int
|
|
|
|
pull_client_data(struct conn_s *connptr, unsigned long int length)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2001-09-12 03:26:49 +08:00
|
|
|
char *buffer;
|
2001-05-27 10:29:06 +08:00
|
|
|
ssize_t len;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2002-04-16 11:20:43 +08:00
|
|
|
buffer = safemalloc(min(MAXBUFFSIZE, length));
|
2001-09-12 03:26:49 +08:00
|
|
|
if (!buffer)
|
|
|
|
return -1;
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
do {
|
2002-04-16 11:20:43 +08:00
|
|
|
len = safe_read(connptr->client_fd, buffer,
|
|
|
|
min(MAXBUFFSIZE, length));
|
|
|
|
if (len <= 0)
|
|
|
|
goto ERROR_EXIT;
|
2000-09-12 08:04:42 +08:00
|
|
|
|
2002-04-15 10:07:27 +08:00
|
|
|
if (!connptr->error_string) {
|
2002-04-16 11:20:43 +08:00
|
|
|
if (safe_write(connptr->server_fd, buffer, len) < 0)
|
|
|
|
goto ERROR_EXIT;
|
2000-09-12 08:04:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
length -= len;
|
|
|
|
} while (length > 0);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-12 03:26:49 +08:00
|
|
|
safefree(buffer);
|
2000-02-17 01:32:49 +08:00
|
|
|
return 0;
|
2002-04-16 11:20:43 +08:00
|
|
|
|
|
|
|
ERROR_EXIT:
|
|
|
|
safefree(buffer);
|
|
|
|
return -1;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
#ifdef XTINYPROXY_ENABLE
|
2000-02-17 01:32:49 +08:00
|
|
|
/*
|
2000-09-12 08:04:42 +08:00
|
|
|
* Add the X-Tinyproxy header to the collection of headers being sent to
|
|
|
|
* the server.
|
|
|
|
* -rjkaes
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static int
|
|
|
|
add_xtinyproxy_header(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2000-09-12 08:04:42 +08:00
|
|
|
char ipaddr[PEER_IP_LENGTH];
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-11-22 03:19:46 +08:00
|
|
|
/*
|
|
|
|
* Don't try to send if we have an invalid server handle.
|
|
|
|
*/
|
2002-04-16 11:20:43 +08:00
|
|
|
if (connptr->server_fd < 0)
|
2001-11-22 03:19:46 +08:00
|
|
|
return 0;
|
|
|
|
|
2001-12-19 13:13:40 +08:00
|
|
|
return write_message(connptr->server_fd,
|
|
|
|
"X-Tinyproxy: %s\r\n",
|
|
|
|
getpeer_ip(connptr->client_fd, ipaddr));
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2001-11-22 08:31:10 +08:00
|
|
|
#endif /* XTINYPROXY */
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
/*
|
|
|
|
* Take a complete header line and break it apart (into a key and the data.)
|
|
|
|
* Now insert this information into the hashmap for the connection so it
|
|
|
|
* can be retrieved and manipulated later.
|
|
|
|
*/
|
|
|
|
static inline int
|
|
|
|
add_header_to_connection(hashmap_t hashofheaders, char *header, size_t len)
|
|
|
|
{
|
|
|
|
char *sep;
|
|
|
|
|
|
|
|
/* Get rid of the new line and return at the end */
|
2002-04-16 11:20:43 +08:00
|
|
|
len -= chomp(header, len);
|
2002-04-08 05:35:59 +08:00
|
|
|
|
|
|
|
sep = strchr(header, ':');
|
|
|
|
if (!sep)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Blank out colons, spaces, and tabs. */
|
|
|
|
while (*sep == ':' || *sep == ' ' || *sep == '\t')
|
|
|
|
*sep++ = '\0';
|
2002-04-16 11:20:43 +08:00
|
|
|
|
|
|
|
/* Calculate the new length of just the data */
|
|
|
|
len -= sep - header - 1;
|
|
|
|
return hashmap_insert(hashofheaders, header, sep, len);
|
2002-04-08 05:35:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read all the headers from the stream
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
get_all_headers(int fd, hashmap_t hashofheaders)
|
|
|
|
{
|
|
|
|
char *header;
|
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
for (;;) {
|
2002-04-19 01:58:52 +08:00
|
|
|
if ((len = readline(fd, &header)) <= 0) {
|
|
|
|
safefree(header);
|
2002-04-08 05:35:59 +08:00
|
|
|
return -1;
|
2002-04-19 01:58:52 +08:00
|
|
|
}
|
2002-04-08 05:35:59 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we received just a CR LF on a line, the headers are
|
|
|
|
* finished.
|
|
|
|
*/
|
2002-04-19 01:58:52 +08:00
|
|
|
if (CHECK_CRLF(header, len)) {
|
|
|
|
safefree(header);
|
2002-04-16 11:20:43 +08:00
|
|
|
return 0;
|
2002-04-19 01:58:52 +08:00
|
|
|
}
|
2002-04-08 05:35:59 +08:00
|
|
|
|
2002-04-19 01:58:52 +08:00
|
|
|
if (add_header_to_connection(hashofheaders, header, len) < 0) {
|
|
|
|
safefree(header);
|
2002-04-08 05:35:59 +08:00
|
|
|
return -1;
|
2002-04-19 01:58:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
safefree(header);
|
2002-04-08 05:35:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extract the headers to remove. These headers were listed in the Connection
|
|
|
|
* header sent via the client (which is stored in data right now.)
|
|
|
|
*/
|
|
|
|
static int
|
2002-04-12 04:44:15 +08:00
|
|
|
remove_connection_headers(hashmap_t hashofheaders)
|
2002-04-08 05:35:59 +08:00
|
|
|
{
|
2002-04-12 04:44:15 +08:00
|
|
|
char *data;
|
2002-04-08 05:35:59 +08:00
|
|
|
char* ptr;
|
2002-04-12 04:44:15 +08:00
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
/* Look for the connection header. If it's not found, return. */
|
|
|
|
len = hashmap_search(hashofheaders, "connection", (void **)&data);
|
|
|
|
if (len <= 0)
|
|
|
|
return 0;
|
2002-04-08 05:35:59 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Go through the data line and replace any special characters with
|
|
|
|
* a NULL.
|
|
|
|
*/
|
|
|
|
ptr = data;
|
2002-04-12 11:09:04 +08:00
|
|
|
while ((ptr = strpbrk(ptr, "()<>@,;:\\\"/[]?={} \t")))
|
2002-04-08 05:35:59 +08:00
|
|
|
*ptr++ = '\0';
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All the tokens are separated by NULLs. Now go through the tokens
|
|
|
|
* 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 == '\0')
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
2002-04-12 04:44:15 +08:00
|
|
|
/* Now remove the connection header it self. */
|
|
|
|
hashmap_remove(hashofheaders, "connection");
|
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-04-12 04:44:15 +08:00
|
|
|
/*
|
|
|
|
* If there is a Content-Length header, then return the value; otherwise, return
|
|
|
|
* a negative number.
|
|
|
|
*/
|
|
|
|
static long
|
|
|
|
get_content_length(hashmap_t hashofheaders)
|
|
|
|
{
|
|
|
|
ssize_t len;
|
|
|
|
char *data;
|
|
|
|
long content_length = -1;
|
|
|
|
|
|
|
|
len = hashmap_search(hashofheaders, "content-length", (void **)&data);
|
2002-04-12 11:09:04 +08:00
|
|
|
if (len > 0)
|
2002-04-12 04:44:15 +08:00
|
|
|
content_length = atol(data);
|
|
|
|
|
|
|
|
return content_length;
|
|
|
|
}
|
|
|
|
|
2002-04-12 11:09:04 +08:00
|
|
|
/*
|
|
|
|
* Search for Via head in a hash of headers and either write a new Via header,
|
|
|
|
* or append our information to the end of an existing Via header.
|
|
|
|
*
|
|
|
|
* FIXME: Need to add code to "hide" our internal information for security
|
|
|
|
* purposes.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
write_via_header(int fd, hashmap_t hashofheaders,
|
|
|
|
unsigned int major, unsigned int minor)
|
|
|
|
{
|
|
|
|
ssize_t len;
|
|
|
|
char hostname[128];
|
|
|
|
char *data;
|
|
|
|
|
|
|
|
gethostname(hostname, sizeof(hostname));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if there is a "Via" header. If so, again we need to do a bit
|
|
|
|
* of processing.
|
|
|
|
*/
|
|
|
|
len = hashmap_search(hashofheaders, "via", (void **)&data);
|
|
|
|
if (len > 0) {
|
|
|
|
write_message(fd,
|
|
|
|
"Via: %s, %hu.%hu %s (%s/%s)\r\n",
|
|
|
|
data,
|
|
|
|
major, minor,
|
|
|
|
hostname, PACKAGE, VERSION);
|
|
|
|
|
|
|
|
hashmap_remove(hashofheaders, "via");
|
|
|
|
} else {
|
|
|
|
write_message(fd,
|
|
|
|
"Via: %hu.%hu %s (%s/%s)\r\n",
|
|
|
|
major, minor,
|
|
|
|
hostname, PACKAGE, VERSION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
/*
|
|
|
|
* Number of buckets to use internally in the hashmap.
|
|
|
|
*/
|
|
|
|
#define HEADER_BUCKETS 32
|
|
|
|
|
2000-02-17 01:32:49 +08:00
|
|
|
/*
|
2000-09-12 08:04:42 +08:00
|
|
|
* Here we loop through all the headers the client is sending. If we
|
|
|
|
* are running in anonymous mode, we will _only_ send the headers listed
|
|
|
|
* (plus a few which are required for various methods).
|
|
|
|
* - rjkaes
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static int
|
|
|
|
process_client_headers(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2001-09-15 03:50:45 +08:00
|
|
|
static char *skipheaders[] = {
|
2001-11-22 03:19:46 +08:00
|
|
|
"host",
|
2001-11-21 08:59:33 +08:00
|
|
|
"keep-alive",
|
|
|
|
"proxy-authenticate",
|
|
|
|
"proxy-authorization",
|
2002-04-23 03:34:50 +08:00
|
|
|
"proxy-connection",
|
2001-12-18 13:01:03 +08:00
|
|
|
"te",
|
|
|
|
"trailers",
|
|
|
|
"transfer-encoding",
|
|
|
|
"upgrade"
|
2000-09-12 08:04:42 +08:00
|
|
|
};
|
|
|
|
int i;
|
2002-04-08 05:35:59 +08:00
|
|
|
hashmap_t hashofheaders;
|
|
|
|
vector_t listofheaders;
|
|
|
|
long content_length = -1;
|
2000-09-12 08:04:42 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
char *data, *header;
|
|
|
|
size_t len;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
hashofheaders = hashmap_create(HEADER_BUCKETS);
|
|
|
|
if (!hashofheaders)
|
|
|
|
return -1;
|
2001-11-23 09:17:19 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
/*
|
|
|
|
* Get all the headers from the client in a big hash.
|
|
|
|
*/
|
|
|
|
if (get_all_headers(connptr->client_fd, hashofheaders) < 0) {
|
2002-04-10 04:06:24 +08:00
|
|
|
log_message(LOG_WARNING, "Could not retrieve all the headers from the client");
|
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
hashmap_delete(hashofheaders);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-04-19 05:43:53 +08:00
|
|
|
* 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.)
|
2002-04-08 05:35:59 +08:00
|
|
|
*/
|
2002-04-19 05:43:53 +08:00
|
|
|
if (connptr->server_fd == -1 || connptr->show_stats
|
2002-04-08 05:35:59 +08:00
|
|
|
|| (connptr->connect_method && !UPSTREAM_CONFIGURED())) {
|
2002-04-10 04:06:24 +08:00
|
|
|
log_message(LOG_INFO, "Not sending client headers to remote machine");
|
2002-04-08 05:35:59 +08:00
|
|
|
hashmap_delete(hashofheaders);
|
|
|
|
return 0;
|
|
|
|
}
|
2001-11-21 08:59:33 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
/*
|
2002-04-12 04:44:15 +08:00
|
|
|
* See if there is a "Content-Length" header. If so, again we need
|
|
|
|
* to do a bit of processing.
|
2002-04-08 05:35:59 +08:00
|
|
|
*/
|
2002-04-12 04:44:15 +08:00
|
|
|
content_length = get_content_length(hashofheaders);
|
2001-09-05 02:22:00 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
/*
|
2002-04-12 04:44:15 +08:00
|
|
|
* See if there is a "Connection" header. If so, we need to do a bit
|
|
|
|
* of processing. :)
|
2002-04-08 05:35:59 +08:00
|
|
|
*/
|
2002-04-12 04:44:15 +08:00
|
|
|
remove_connection_headers(hashofheaders);
|
2000-09-12 08:04:42 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
/*
|
|
|
|
* Delete the headers listed in the skipheaders list
|
|
|
|
*/
|
|
|
|
for (i = 0; i < (sizeof(skipheaders) / sizeof(char *)); i++) {
|
|
|
|
hashmap_remove(hashofheaders, skipheaders[i]);
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2002-04-12 11:09:04 +08:00
|
|
|
/* Send, or add the Via header */
|
|
|
|
write_via_header(connptr->server_fd, hashofheaders,
|
|
|
|
connptr->protocol.major, connptr->protocol.minor);
|
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
/*
|
|
|
|
* Output all the remaining headers to the remote machine.
|
|
|
|
*/
|
|
|
|
listofheaders = hashmap_keys(hashofheaders);
|
|
|
|
for (i = 0; i < vector_length(listofheaders); i++) {
|
|
|
|
len = vector_getentry(listofheaders, i, (void **)&data);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
hashmap_search(hashofheaders, data, (void **)&header);
|
2001-12-17 08:11:32 +08:00
|
|
|
|
2002-04-16 11:20:43 +08:00
|
|
|
if (!is_anonymous_enabled() || anonymous_search(data) <= 0) {
|
2001-12-24 05:55:08 +08:00
|
|
|
write_message(connptr->server_fd,
|
2002-04-08 05:35:59 +08:00
|
|
|
"%s: %s\r\n",
|
|
|
|
data, header);
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
}
|
2002-04-08 05:35:59 +08:00
|
|
|
vector_delete(listofheaders);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
/* Free the hashofheaders since it's no longer needed */
|
|
|
|
hashmap_delete(hashofheaders);
|
|
|
|
|
|
|
|
#if defined(XTINYPROXY_ENABLE)
|
2002-04-10 04:06:24 +08:00
|
|
|
if (config.my_domain)
|
|
|
|
add_xtinyproxy_header(connptr);
|
2002-04-08 05:35:59 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Write the final "blank" line to signify the end of the headers */
|
|
|
|
safe_write(connptr->server_fd, "\r\n", 2);
|
2001-09-12 03:26:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
|
|
|
* Spin here pulling the data from the client.
|
|
|
|
*/
|
|
|
|
if (content_length >= 0)
|
2001-11-22 08:31:10 +08:00
|
|
|
return pull_client_data(connptr,
|
|
|
|
(unsigned long int) content_length);
|
2000-09-12 08:04:42 +08:00
|
|
|
else
|
|
|
|
return 0;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-09-12 08:04:42 +08:00
|
|
|
* Loop through all the headers (including the response code) from the
|
|
|
|
* server.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static int
|
|
|
|
process_server_headers(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2002-04-12 11:09:04 +08:00
|
|
|
static char *skipheaders[] = {
|
|
|
|
"keep-alive",
|
|
|
|
"proxy-authenticate",
|
|
|
|
"proxy-authorization",
|
2002-04-25 00:47:19 +08:00
|
|
|
"proxy-connection",
|
2002-04-12 11:09:04 +08:00
|
|
|
"transfer-encoding",
|
|
|
|
};
|
|
|
|
|
2002-04-12 04:44:15 +08:00
|
|
|
char *response_line;
|
|
|
|
|
|
|
|
hashmap_t hashofheaders;
|
|
|
|
vector_t listofheaders;
|
|
|
|
char *data, *header;
|
2001-12-20 04:40:23 +08:00
|
|
|
ssize_t len;
|
2002-04-12 04:44:15 +08:00
|
|
|
int i;
|
2001-09-12 03:26:49 +08:00
|
|
|
|
2002-04-12 04:44:15 +08:00
|
|
|
/* FIXME: Remember to handle a "simple_req" type */
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2002-04-12 04:44:15 +08:00
|
|
|
/* Get the response line from the remote server. */
|
|
|
|
if ((len = readline(connptr->server_fd, &response_line)) <= 0)
|
|
|
|
return -1;
|
2001-11-22 08:31:10 +08:00
|
|
|
|
2002-04-12 04:44:15 +08:00
|
|
|
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);
|
|
|
|
return -1;
|
|
|
|
}
|
2001-12-20 04:40:23 +08:00
|
|
|
|
2002-04-12 11:09:04 +08:00
|
|
|
/* Send the saved response line first */
|
|
|
|
safe_write(connptr->client_fd, response_line, strlen(response_line));
|
|
|
|
safefree(response_line);
|
|
|
|
|
2002-04-12 04:44:15 +08:00
|
|
|
/*
|
|
|
|
* If there is a "Content-Length" header, retrieve the information
|
|
|
|
* from it for later use.
|
|
|
|
*/
|
|
|
|
connptr->remote_content_length = 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);
|
|
|
|
|
2002-04-12 11:09:04 +08:00
|
|
|
/*
|
|
|
|
* 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 */
|
|
|
|
write_via_header(connptr->client_fd, hashofheaders,
|
|
|
|
connptr->protocol.major, connptr->protocol.minor);
|
2002-04-12 04:44:15 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Okay, output all the remaining headers to the client.
|
|
|
|
*/
|
|
|
|
listofheaders = hashmap_keys(hashofheaders);
|
|
|
|
for (i = 0; i < vector_length(listofheaders); ++i) {
|
|
|
|
len = vector_getentry(listofheaders, i, (void **)&data);
|
|
|
|
hashmap_search(hashofheaders, data, (void **)&header);
|
|
|
|
|
|
|
|
write_message(connptr->client_fd,
|
|
|
|
"%s: %s\r\n",
|
|
|
|
data, header);
|
2000-09-12 08:04:42 +08:00
|
|
|
}
|
2002-04-12 04:44:15 +08:00
|
|
|
vector_delete(listofheaders);
|
|
|
|
hashmap_delete(hashofheaders);
|
|
|
|
|
|
|
|
/* Write the final blank line to signify the end of the headers */
|
|
|
|
safe_write(connptr->client_fd, "\r\n", 2);
|
2001-09-12 03:26:49 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
return 0;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
|
|
|
* Switch the sockets into nonblocking mode and begin relaying the bytes
|
|
|
|
* between the two connections. We continue to use the buffering code
|
|
|
|
* since we want to be able to buffer a certain amount for slower
|
|
|
|
* connections (as this was the reason why I originally modified
|
|
|
|
* tinyproxy oh so long ago...)
|
|
|
|
* - rjkaes
|
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static void
|
|
|
|
relay_connection(struct conn_s *connptr)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2000-09-12 08:04:42 +08:00
|
|
|
fd_set rset, wset;
|
|
|
|
struct timeval tv;
|
|
|
|
time_t last_access;
|
|
|
|
int ret;
|
|
|
|
double tdiff;
|
2001-05-27 10:29:06 +08:00
|
|
|
int maxfd = max(connptr->client_fd, connptr->server_fd) + 1;
|
2002-04-12 04:44:15 +08:00
|
|
|
ssize_t bytes_received;
|
2000-09-12 08:04:42 +08:00
|
|
|
|
|
|
|
socket_nonblocking(connptr->client_fd);
|
|
|
|
socket_nonblocking(connptr->server_fd);
|
|
|
|
|
|
|
|
last_access = time(NULL);
|
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
for (;;) {
|
2000-09-12 08:04:42 +08:00
|
|
|
FD_ZERO(&rset);
|
|
|
|
FD_ZERO(&wset);
|
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
tv.tv_sec =
|
|
|
|
config.idletimeout - difftime(time(NULL), last_access);
|
2000-09-12 08:04:42 +08:00
|
|
|
tv.tv_usec = 0;
|
|
|
|
|
2001-11-05 23:23:34 +08:00
|
|
|
if (BUFFER_SIZE(connptr->sbuffer) > 0)
|
2000-09-12 08:04:42 +08:00
|
|
|
FD_SET(connptr->client_fd, &wset);
|
2001-11-05 23:23:34 +08:00
|
|
|
if (BUFFER_SIZE(connptr->cbuffer) > 0)
|
2000-09-12 08:04:42 +08:00
|
|
|
FD_SET(connptr->server_fd, &wset);
|
2001-11-05 23:23:34 +08:00
|
|
|
if (BUFFER_SIZE(connptr->sbuffer) < MAXBUFFSIZE)
|
2000-09-12 08:04:42 +08:00
|
|
|
FD_SET(connptr->server_fd, &rset);
|
2001-11-05 23:23:34 +08:00
|
|
|
if (BUFFER_SIZE(connptr->cbuffer) < MAXBUFFSIZE)
|
2000-09-12 08:04:42 +08:00
|
|
|
FD_SET(connptr->client_fd, &rset);
|
|
|
|
|
2001-05-27 10:29:06 +08:00
|
|
|
ret = select(maxfd, &rset, &wset, NULL, &tv);
|
2001-05-24 01:58:19 +08:00
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
if (ret == 0) {
|
|
|
|
tdiff = difftime(time(NULL), last_access);
|
|
|
|
if (tdiff > config.idletimeout) {
|
2001-11-22 08:31:10 +08:00
|
|
|
log_message(LOG_INFO,
|
|
|
|
"Idle Timeout (after select) as %g > %u.",
|
|
|
|
tdiff, config.idletimeout);
|
2000-02-17 01:32:49 +08:00
|
|
|
return;
|
2000-09-12 08:04:42 +08:00
|
|
|
} else {
|
|
|
|
continue;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2001-05-27 10:29:06 +08:00
|
|
|
} else if (ret < 0) {
|
2001-11-22 08:31:10 +08:00
|
|
|
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);
|
2000-09-12 08:04:42 +08:00
|
|
|
return;
|
2001-05-27 10:29:06 +08:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Okay, something was actually selected so mark it.
|
|
|
|
*/
|
|
|
|
last_access = time(NULL);
|
|
|
|
}
|
2001-11-22 08:31:10 +08:00
|
|
|
|
2002-04-12 04:44:15 +08:00
|
|
|
if (FD_ISSET(connptr->server_fd, &rset)) {
|
|
|
|
bytes_received = read_buffer(connptr->server_fd, connptr->sbuffer);
|
|
|
|
if (bytes_received < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
connptr->remote_content_length -= bytes_received;
|
|
|
|
if (connptr->remote_content_length == 0)
|
|
|
|
break;
|
2000-09-12 08:04:42 +08:00
|
|
|
}
|
2001-05-27 10:29:06 +08:00
|
|
|
if (FD_ISSET(connptr->client_fd, &rset)
|
2001-12-17 08:11:32 +08:00
|
|
|
&& read_buffer(connptr->client_fd, connptr->cbuffer) < 0) {
|
2001-10-25 12:40:48 +08:00
|
|
|
break;
|
2000-09-12 08:04:42 +08:00
|
|
|
}
|
2001-05-27 10:29:06 +08:00
|
|
|
if (FD_ISSET(connptr->server_fd, &wset)
|
2001-12-17 08:11:32 +08:00
|
|
|
&& write_buffer(connptr->server_fd, connptr->cbuffer) < 0) {
|
2001-05-30 23:45:14 +08:00
|
|
|
break;
|
2000-09-12 08:04:42 +08:00
|
|
|
}
|
2001-05-27 10:29:06 +08:00
|
|
|
if (FD_ISSET(connptr->client_fd, &wset)
|
2001-12-17 08:11:32 +08:00
|
|
|
&& write_buffer(connptr->client_fd, connptr->sbuffer) < 0) {
|
2001-10-25 12:40:48 +08:00
|
|
|
break;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
|
|
|
* Here the server has closed the connection... write the
|
|
|
|
* remainder to the client and then exit.
|
|
|
|
*/
|
|
|
|
socket_blocking(connptr->client_fd);
|
2001-11-05 23:23:34 +08:00
|
|
|
while (BUFFER_SIZE(connptr->sbuffer) > 0) {
|
2001-12-17 08:11:32 +08:00
|
|
|
if (write_buffer(connptr->client_fd, connptr->sbuffer) < 0)
|
2001-10-25 12:40:48 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Try to send any remaining data to the server if we can.
|
|
|
|
*/
|
|
|
|
socket_blocking(connptr->server_fd);
|
2001-11-05 23:23:34 +08:00
|
|
|
while (BUFFER_SIZE(connptr->cbuffer) > 0) {
|
2001-12-17 08:11:32 +08:00
|
|
|
if (write_buffer(connptr->client_fd, connptr->cbuffer) < 0)
|
2001-10-25 12:40:48 +08:00
|
|
|
break;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2000-09-12 08:04:42 +08:00
|
|
|
|
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-10-20 02:03:49 +08:00
|
|
|
#ifdef UPSTREAM_SUPPORT
|
|
|
|
/*
|
|
|
|
* Establish a connection to the upstream proxy server.
|
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static int
|
|
|
|
connect_to_upstream(struct conn_s *connptr, struct request_s *request)
|
2001-10-20 02:03:49 +08:00
|
|
|
{
|
2001-10-25 12:40:48 +08:00
|
|
|
char *combined_string;
|
2001-10-20 02:03:49 +08:00
|
|
|
int len;
|
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
connptr->server_fd =
|
|
|
|
opensock(config.upstream_name, config.upstream_port);
|
2001-10-20 02:03:49 +08:00
|
|
|
|
|
|
|
if (connptr->server_fd < 0) {
|
2001-11-22 08:31:10 +08:00
|
|
|
log_message(LOG_WARNING,
|
|
|
|
"Could not connect to upstream proxy.");
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 404, "Unable to connect to upstream proxy.");
|
2001-10-20 02:03:49 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
log_message(LOG_CONN,
|
|
|
|
"Established connection to upstream proxy \"%s\" using file descriptor %d.",
|
|
|
|
config.upstream_name, connptr->server_fd);
|
2001-10-20 02:03:49 +08:00
|
|
|
|
2001-10-25 12:40:48 +08:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2001-12-17 08:11:32 +08:00
|
|
|
if (connptr->connect_method) {
|
2001-10-25 12:40:48 +08:00
|
|
|
len = strlen(request->host) + 6;
|
2001-10-20 02:03:49 +08:00
|
|
|
|
2001-10-25 12:40:48 +08:00
|
|
|
combined_string = safemalloc(len + 1);
|
|
|
|
if (!combined_string) {
|
|
|
|
return -1;
|
|
|
|
}
|
2001-10-20 02:03:49 +08:00
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
snprintf(combined_string, len, "%s:%d", request->host,
|
|
|
|
request->port);
|
2001-10-25 12:40:48 +08:00
|
|
|
} else {
|
|
|
|
len = strlen(request->host) + strlen(request->path) + 14;
|
|
|
|
combined_string = safemalloc(len + 1);
|
|
|
|
if (!combined_string) {
|
|
|
|
return -1;
|
|
|
|
}
|
2001-10-20 02:03:49 +08:00
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
snprintf(combined_string, len, "http://%s:%d%s", request->host,
|
|
|
|
request->port, request->path);
|
2001-10-25 12:40:48 +08:00
|
|
|
}
|
2001-10-20 02:03:49 +08:00
|
|
|
|
|
|
|
safefree(request->path);
|
2001-10-25 12:40:48 +08:00
|
|
|
request->path = combined_string;
|
2001-11-22 08:31:10 +08:00
|
|
|
|
2001-10-20 02:03:49 +08:00
|
|
|
return establish_http_connection(connptr, request);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-12-19 13:13:40 +08:00
|
|
|
#ifdef TUNNEL_SUPPORT
|
|
|
|
/*
|
|
|
|
* If tunnel has been configured then redirect any connections to it.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
connect_to_tunnel(struct conn_s *connptr)
|
|
|
|
{
|
|
|
|
char *request_buf;
|
|
|
|
size_t len;
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
request_buf = safemalloc(HTTP_LINE_LENGTH);
|
|
|
|
if (request_buf) {
|
|
|
|
len = recv(connptr->client_fd, request_buf, HTTP_LINE_LENGTH - 1, MSG_PEEK);
|
|
|
|
for (pos = 0; pos < len && request_buf[pos] != '\n'; pos++)
|
|
|
|
;
|
|
|
|
request_buf[pos] = '\0';
|
|
|
|
|
|
|
|
log_message(LOG_CONN, "Request: %s", request_buf);
|
|
|
|
|
|
|
|
safefree(request_buf);
|
|
|
|
}
|
|
|
|
log_message(LOG_INFO, "Redirecting to %s:%d",
|
|
|
|
config.tunnel_name, config.tunnel_port);
|
|
|
|
|
|
|
|
connptr->server_fd =
|
|
|
|
opensock(config.tunnel_name, config.tunnel_port);
|
|
|
|
|
|
|
|
if (connptr->server_fd < 0) {
|
|
|
|
log_message(LOG_WARNING,
|
|
|
|
"Could not connect to tunnel.");
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 404, "Unable to connect to tunnel.");
|
2001-12-19 13:13:40 +08:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_message(LOG_INFO,
|
|
|
|
"Established a connection to the tunnel \"%s\" using file descriptor %d.",
|
|
|
|
config.tunnel_name, connptr->server_fd);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-02-17 01:32:49 +08:00
|
|
|
/*
|
2000-09-12 08:04:42 +08:00
|
|
|
* This is the main drive for each connection. As you can tell, for the
|
|
|
|
* first few steps we are using a blocking socket. If you remember the
|
|
|
|
* older tinyproxy code, this use to be a very confusing state machine.
|
|
|
|
* Well, no more! :) The sockets are only switched into nonblocking mode
|
|
|
|
* when we start the relay portion. This makes most of the original
|
|
|
|
* tinyproxy code, which was confusing, redundant. Hail progress.
|
|
|
|
* - rjkaes
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
void
|
|
|
|
handle_connection(int fd)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
|
|
|
struct conn_s *connptr;
|
2001-10-20 02:03:49 +08:00
|
|
|
struct request_s *request = NULL;
|
2001-09-17 04:10:19 +08:00
|
|
|
|
2000-02-17 01:32:49 +08:00
|
|
|
char peer_ipaddr[PEER_IP_LENGTH];
|
2000-09-12 08:04:42 +08:00
|
|
|
char peer_string[PEER_STRING_LENGTH];
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2001-09-14 12:56:29 +08:00
|
|
|
log_message(LOG_CONN, "Connect (file descriptor %d): %s [%s]",
|
|
|
|
fd,
|
2001-08-27 05:11:55 +08:00
|
|
|
getpeer_string(fd, peer_string),
|
|
|
|
getpeer_ip(fd, peer_ipaddr));
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
connptr = initialize_conn(fd);
|
2002-04-18 04:55:21 +08:00
|
|
|
if (!connptr) {
|
|
|
|
close(fd);
|
2000-09-12 08:04:42 +08:00
|
|
|
return;
|
2002-04-18 04:55:21 +08:00
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2002-04-18 04:55:21 +08:00
|
|
|
if (check_acl(fd, peer_ipaddr, peer_string) <= 0) {
|
2000-09-12 08:04:42 +08:00
|
|
|
update_stats(STAT_DENIED);
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 403,
|
2001-11-22 08:31:10 +08:00
|
|
|
"You do not have authorization for using this service.");
|
2000-09-12 08:04:42 +08:00
|
|
|
goto send_error;
|
|
|
|
}
|
2001-12-18 03:10:56 +08:00
|
|
|
|
2001-12-19 13:13:40 +08:00
|
|
|
if (TUNNEL_CONFIGURED()) {
|
|
|
|
if (connect_to_tunnel(connptr) < 0)
|
2000-09-12 08:04:42 +08:00
|
|
|
goto internal_proxy;
|
2001-12-19 13:13:40 +08:00
|
|
|
else
|
|
|
|
goto relay_proxy;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
internal_proxy:
|
2002-04-08 05:35:59 +08:00
|
|
|
if (read_request_line(connptr) < 0) {
|
2001-09-17 04:10:19 +08:00
|
|
|
update_stats(STAT_BADCONN);
|
2000-09-12 08:04:42 +08:00
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2002-04-08 05:35:59 +08:00
|
|
|
request = process_request(connptr);
|
2001-09-17 04:10:19 +08:00
|
|
|
if (!request) {
|
2002-04-19 05:43:53 +08:00
|
|
|
if (!connptr->error_string && !connptr->show_stats) {
|
2001-10-23 00:08:29 +08:00
|
|
|
update_stats(STAT_BADCONN);
|
2001-09-17 04:10:19 +08:00
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
|
|
|
}
|
2001-10-23 00:08:29 +08:00
|
|
|
goto send_error;
|
|
|
|
}
|
2001-10-25 13:12:46 +08:00
|
|
|
|
2001-12-17 08:11:32 +08:00
|
|
|
if (UPSTREAM_CONFIGURED()) {
|
2001-10-23 00:08:29 +08:00
|
|
|
if (connect_to_upstream(connptr, request) < 0)
|
|
|
|
goto send_error;
|
|
|
|
} else {
|
|
|
|
connptr->server_fd = opensock(request->host, request->port);
|
|
|
|
if (connptr->server_fd < 0) {
|
2002-04-15 10:07:27 +08:00
|
|
|
indicate_http_error(connptr, 500, HTTP500ERROR);
|
2001-10-23 00:08:29 +08:00
|
|
|
goto send_error;
|
|
|
|
}
|
2001-09-17 04:10:19 +08:00
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
log_message(LOG_CONN,
|
|
|
|
"Established connection to host \"%s\" using file descriptor %d.",
|
|
|
|
request->host, connptr->server_fd);
|
2001-10-20 02:03:49 +08:00
|
|
|
|
2001-12-17 08:11:32 +08:00
|
|
|
if (!connptr->connect_method)
|
2001-10-23 00:08:29 +08:00
|
|
|
establish_http_connection(connptr, request);
|
2001-09-17 04:10:19 +08:00
|
|
|
}
|
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
send_error:
|
2001-10-20 02:03:49 +08:00
|
|
|
free_request_struct(request);
|
|
|
|
|
2001-12-17 08:11:32 +08:00
|
|
|
if (process_client_headers(connptr) < 0) {
|
|
|
|
update_stats(STAT_BADCONN);
|
2002-04-15 10:07:27 +08:00
|
|
|
if (!connptr->error_string) {
|
2001-12-17 08:11:32 +08:00
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-04-15 10:07:27 +08:00
|
|
|
if (connptr->error_string) {
|
|
|
|
send_http_error_message(connptr);
|
2000-09-12 08:04:42 +08:00
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
2002-04-19 05:43:53 +08:00
|
|
|
} else if (connptr->show_stats) {
|
|
|
|
showstats(connptr);
|
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-12-17 08:11:32 +08:00
|
|
|
if (!connptr->connect_method || UPSTREAM_CONFIGURED()) {
|
2001-09-14 12:56:29 +08:00
|
|
|
if (process_server_headers(connptr) < 0) {
|
|
|
|
update_stats(STAT_BADCONN);
|
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2001-09-16 05:26:14 +08:00
|
|
|
if (send_ssl_response(connptr) < 0) {
|
2001-11-22 08:31:10 +08:00
|
|
|
log_message(LOG_ERR,
|
|
|
|
"handle_connection: Could not send SSL greeting to client.");
|
2001-09-17 04:10:19 +08:00
|
|
|
update_stats(STAT_BADCONN);
|
2001-09-14 12:56:29 +08:00
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
relay_proxy:
|
2000-09-12 08:04:42 +08:00
|
|
|
relay_connection(connptr);
|
|
|
|
|
2002-04-12 04:44:15 +08:00
|
|
|
log_message(LOG_INFO, "Closed connection between local client (fd:%d) and remote client (fd:%d)",
|
|
|
|
connptr->client_fd, connptr->server_fd);
|
|
|
|
|
2000-09-12 08:04:42 +08:00
|
|
|
/*
|
|
|
|
* All done... close everything and go home... :)
|
|
|
|
*/
|
|
|
|
destroy_conn(connptr);
|
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|