Modify proxy to handle multiple HTTP requests per connection

- Keep connection open for persistent HTTP connections
- Prevents premature connection closure that causes browser errors
- Loop processing requests until client closes connection
parent df1bc6ab
......@@ -389,288 +389,297 @@ static void *proxy_data_forward(void *arg) {
// Handle incoming HTTP request by proxying to wsssht daemon
static int handle_proxy_request(int client_fd, wssshd_state_t *state, const wssshd_config_t *config) {
char request[8192];
ssize_t bytes_read = recv(client_fd, request, sizeof(request) - 1, 0);
if (bytes_read <= 0) {
return -1;
}
request[bytes_read] = '\0';
// Parse Host header
char hostname[256];
if (parse_host_header(request, hostname, sizeof(hostname)) != 0) {
send_http_error(client_fd, 400, "Bad Request");
return -1;
}
printf("[WEB-PROXY] Received request for hostname: %s\n", hostname);
// Find client by hostname
// Find client once, assume all requests on this connection are for the same hostname
char first_hostname[256] = {0};
client_t *client = NULL;
pthread_mutex_lock(&state->client_mutex);
for (size_t i = 0; i < state->clients_count; i++) {
client_t *c = &state->clients[i];
if (!c->active) continue;
int hostname_match = 0;
if (strcasecmp(hostname, c->client_id) == 0) {
hostname_match = 1;
} else if (config && config->domain) {
char expected_hostname[512];
snprintf(expected_hostname, sizeof(expected_hostname), "%s.%s", c->client_id, config->domain);
if (strcasecmp(hostname, expected_hostname) == 0) {
hostname_match = 1;
}
}
const char *service_type = NULL;
if (hostname_match) {
client = c;
while (1) {
char request[8192];
ssize_t bytes_read = recv(client_fd, request, sizeof(request) - 1, 0);
if (bytes_read <= 0) {
break;
}
}
pthread_mutex_unlock(&state->client_mutex);
request[bytes_read] = '\0';
if (!client) {
printf("[WEB-PROXY] No client found for hostname: %s\n", hostname);
send_http_error(client_fd, 404, "Not Found");
return -1;
}
// Parse Host header
char hostname[256];
if (parse_host_header(request, hostname, sizeof(hostname)) != 0) {
send_http_error(client_fd, 400, "Bad Request");
continue;
}
printf("[WEB-PROXY] Found client: %s\n", client->client_id);
printf("[WEB-PROXY] Received request for hostname: %s\n", hostname);
// Find client by hostname (only once)
if (!client || strcmp(first_hostname, hostname) != 0) {
strcpy(first_hostname, hostname);
pthread_mutex_lock(&state->client_mutex);
for (size_t i = 0; i < state->clients_count; i++) {
client_t *c = &state->clients[i];
if (!c->active) continue;
int hostname_match = 0;
if (strcasecmp(hostname, c->client_id) == 0) {
hostname_match = 1;
} else if (config && config->domain) {
char expected_hostname[512];
snprintf(expected_hostname, sizeof(expected_hostname), "%s.%s", c->client_id, config->domain);
if (strcasecmp(hostname, expected_hostname) == 0) {
hostname_match = 1;
}
}
// Check if client has web/http/https services
bool has_web_service = false;
const char *service_type = NULL;
char *services_copy = strdup(client->services);
if (services_copy) {
char *service_token = strtok(services_copy, ",");
while (service_token) {
while (*service_token == ' ' || *service_token == '\t') service_token++;
char *end = service_token + strlen(service_token) - 1;
while (end > service_token && (*end == ' ' || *end == '\t')) {
*end = '\0';
end--;
if (hostname_match) {
client = c;
break;
}
}
pthread_mutex_unlock(&state->client_mutex);
if (strncmp(service_token, "web", 3) == 0) {
has_web_service = true;
service_type = "web";
break;
} else if (strncmp(service_token, "http", 4) == 0) {
has_web_service = true;
service_type = "http";
break;
} else if (strncmp(service_token, "https", 5) == 0) {
has_web_service = true;
service_type = "https";
break;
if (!client) {
printf("[WEB-PROXY] No client found for hostname: %s\n", hostname);
send_http_error(client_fd, 404, "Not Found");
continue;
}
service_token = strtok(NULL, ",");
}
free(services_copy);
}
printf("[WEB-PROXY] Found client: %s\n", client->client_id);
// Check if client has web/http/https services
bool has_web_service = false;
char *services_copy = strdup(client->services);
if (services_copy) {
char *service_token = strtok(services_copy, ",");
while (service_token) {
while (*service_token == ' ' || *service_token == '\t') service_token++;
char *end = service_token + strlen(service_token) - 1;
while (end > service_token && (*end == ' ' || *end == '\t')) {
*end = '\0';
end--;
}
if (!has_web_service) {
printf("[WEB-PROXY] Client %s does not have web/http/https services\n", client->client_id);
send_http_error(client_fd, 503, "Service Unavailable");
return -1;
}
if (strncmp(service_token, "web", 3) == 0) {
has_web_service = true;
service_type = "web";
break;
} else if (strncmp(service_token, "http", 4) == 0) {
has_web_service = true;
service_type = "http";
break;
} else if (strncmp(service_token, "https", 5) == 0) {
has_web_service = true;
service_type = "https";
break;
}
// Determine if SSL should be used
bool use_ssl = false;
if (strcmp(service_type, "https") == 0) {
use_ssl = true;
printf("[WEB-PROXY] Service type 'https', using SSL\n");
} else if (strcmp(service_type, "web") == 0) {
use_ssl = true; // Try HTTPS first for 'web'
printf("[WEB-PROXY] Service type 'web', trying SSL first\n");
} else {
printf("[WEB-PROXY] Service type '%s', using plain TCP\n", service_type);
}
service_token = strtok(NULL, ",");
}
free(services_copy);
}
// Find or create wsssht process
wsssht_process_t *proc = find_or_create_wsssht_process(hostname, service_type, client->client_id, config->domain);
if (!proc) {
printf("[WEB-PROXY] Failed to launch wsssht daemon for %s\n", hostname);
send_http_error(client_fd, 502, "Bad Gateway");
return -1;
}
if (!has_web_service) {
printf("[WEB-PROXY] Client %s does not have web/http/https services\n", client->client_id);
send_http_error(client_fd, 503, "Service Unavailable");
continue;
}
}
// Connect to wsssht daemon
int tunnel_fd = socket(AF_INET, SOCK_STREAM, 0);
if (tunnel_fd < 0) {
perror("[WEB-PROXY] Failed to create socket");
send_http_error(client_fd, 500, "Internal Server Error");
return -1;
}
// Determine if SSL should be used
bool use_ssl = false;
if (strcmp(service_type, "https") == 0) {
use_ssl = true;
printf("[WEB-PROXY] Service type 'https', using SSL\n");
} else if (strcmp(service_type, "web") == 0) {
use_ssl = true; // Try HTTPS first for 'web'
printf("[WEB-PROXY] Service type 'web', trying SSL first\n");
} else {
printf("[WEB-PROXY] Service type '%s', using plain TCP\n", service_type);
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(proc->port);
// Find or create wsssht process
wsssht_process_t *proc = find_or_create_wsssht_process(hostname, service_type, client->client_id, config->domain);
if (!proc) {
printf("[WEB-PROXY] Failed to launch wsssht daemon for %s\n", hostname);
send_http_error(client_fd, 502, "Bad Gateway");
continue;
}
printf("[WEB-PROXY] Connecting to wsssht on localhost:%d\n", proc->port);
if (connect(tunnel_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("[WEB-PROXY] Failed to connect to wsssht");
close(tunnel_fd);
send_http_error(client_fd, 502, "Bad Gateway");
return -1;
}
printf("[WEB-PROXY] Connected to wsssht\n");
// SSL setup if needed
SSL_CTX *ssl_ctx = NULL;
SSL *tunnel_ssl = NULL;
if (use_ssl) {
printf("[WEB-PROXY] Setting up SSL connection\n");
ssl_ctx = create_ssl_context();
if (!ssl_ctx) {
printf("[WEB-PROXY] Failed to create SSL context\n");
if (strcmp(service_type, "web") == 0) {
use_ssl = false; // Fallback to HTTP
printf("[WEB-PROXY] Falling back to plain TCP\n");
} else {
close(tunnel_fd);
send_http_error(client_fd, 502, "Bad Gateway");
return -1;
}
} else {
// Set socket non-blocking for SSL timeout
int flags = fcntl(tunnel_fd, F_GETFL, 0);
fcntl(tunnel_fd, F_SETFL, flags | O_NONBLOCK);
tunnel_ssl = SSL_new(ssl_ctx);
SSL_set_fd(tunnel_ssl, tunnel_fd);
// Perform SSL connect with timeout
int ret;
fd_set fdset;
struct timeval tv;
tv.tv_sec = 5; // 5 second timeout
tv.tv_usec = 0;
// Connect to wsssht daemon
int tunnel_fd = socket(AF_INET, SOCK_STREAM, 0);
if (tunnel_fd < 0) {
perror("[WEB-PROXY] Failed to create socket");
send_http_error(client_fd, 500, "Internal Server Error");
continue;
}
while (1) {
ret = SSL_connect(tunnel_ssl);
if (ret > 0) {
printf("[WEB-PROXY] SSL connection established\n");
break;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(proc->port);
printf("[WEB-PROXY] Connecting to wsssht on localhost:%d\n", proc->port);
if (connect(tunnel_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("[WEB-PROXY] Failed to connect to wsssht");
close(tunnel_fd);
send_http_error(client_fd, 502, "Bad Gateway");
continue;
}
printf("[WEB-PROXY] Connected to wsssht\n");
// SSL setup if needed
SSL_CTX *ssl_ctx = NULL;
SSL *tunnel_ssl = NULL;
if (use_ssl) {
printf("[WEB-PROXY] Setting up SSL connection\n");
ssl_ctx = create_ssl_context();
if (!ssl_ctx) {
printf("[WEB-PROXY] Failed to create SSL context\n");
if (strcmp(service_type, "web") == 0) {
use_ssl = false; // Fallback to HTTP
printf("[WEB-PROXY] Falling back to plain TCP\n");
} else {
close(tunnel_fd);
send_http_error(client_fd, 502, "Bad Gateway");
continue;
}
int err = SSL_get_error(tunnel_ssl, ret);
if (err == SSL_ERROR_WANT_READ) {
FD_ZERO(&fdset);
FD_SET(tunnel_fd, &fdset);
int sel = select(tunnel_fd + 1, &fdset, NULL, NULL, &tv);
if (sel <= 0) {
printf("[WEB-PROXY] SSL connection timeout on read\n");
ret = -1;
} else {
// Set socket non-blocking for SSL timeout
int flags = fcntl(tunnel_fd, F_GETFL, 0);
fcntl(tunnel_fd, F_SETFL, flags | O_NONBLOCK);
tunnel_ssl = SSL_new(ssl_ctx);
SSL_set_fd(tunnel_ssl, tunnel_fd);
// Perform SSL connect with timeout
int ret;
fd_set fdset;
struct timeval tv;
tv.tv_sec = 5; // 5 second timeout
tv.tv_usec = 0;
while (1) {
ret = SSL_connect(tunnel_ssl);
if (ret > 0) {
printf("[WEB-PROXY] SSL connection established\n");
break;
}
} else if (err == SSL_ERROR_WANT_WRITE) {
FD_ZERO(&fdset);
FD_SET(tunnel_fd, &fdset);
int sel = select(tunnel_fd + 1, NULL, &fdset, NULL, &tv);
if (sel <= 0) {
printf("[WEB-PROXY] SSL connection timeout on write\n");
int err = SSL_get_error(tunnel_ssl, ret);
if (err == SSL_ERROR_WANT_READ) {
FD_ZERO(&fdset);
FD_SET(tunnel_fd, &fdset);
int sel = select(tunnel_fd + 1, &fdset, NULL, NULL, &tv);
if (sel <= 0) {
printf("[WEB-PROXY] SSL connection timeout on read\n");
ret = -1;
break;
}
} else if (err == SSL_ERROR_WANT_WRITE) {
FD_ZERO(&fdset);
FD_SET(tunnel_fd, &fdset);
int sel = select(tunnel_fd + 1, NULL, &fdset, NULL, &tv);
if (sel <= 0) {
printf("[WEB-PROXY] SSL connection timeout on write\n");
ret = -1;
break;
}
} else {
printf("[WEB-PROXY] SSL connection failed with error %d\n", err);
ret = -1;
break;
}
} else {
printf("[WEB-PROXY] SSL connection failed with error %d\n", err);
ret = -1;
break;
}
}
if (ret <= 0) {
SSL_free(tunnel_ssl);
tunnel_ssl = NULL;
SSL_CTX_free(ssl_ctx);
ssl_ctx = NULL;
if (strcmp(service_type, "web") == 0) {
use_ssl = false; // Fallback to HTTP
printf("[WEB-PROXY] Falling back to plain TCP\n");
} else {
close(tunnel_fd);
send_http_error(client_fd, 502, "Bad Gateway");
return -1;
if (ret <= 0) {
SSL_free(tunnel_ssl);
tunnel_ssl = NULL;
SSL_CTX_free(ssl_ctx);
ssl_ctx = NULL;
if (strcmp(service_type, "web") == 0) {
use_ssl = false; // Fallback to HTTP
printf("[WEB-PROXY] Falling back to plain TCP\n");
} else {
close(tunnel_fd);
send_http_error(client_fd, 502, "Bad Gateway");
continue;
}
}
// Set socket back to blocking
if (tunnel_ssl) {
fcntl(tunnel_fd, F_SETFL, flags & ~O_NONBLOCK);
}
}
}
// Set socket back to blocking
// Send HTTP request to wsssht daemon
int send_result;
if (use_ssl) {
send_result = SSL_write(tunnel_ssl, request, bytes_read);
} else {
send_result = send(tunnel_fd, request, bytes_read, 0);
}
if (send_result != bytes_read) {
if (tunnel_ssl) {
fcntl(tunnel_fd, F_SETFL, flags & ~O_NONBLOCK);
SSL_shutdown(tunnel_ssl);
SSL_free(tunnel_ssl);
}
if (ssl_ctx) SSL_CTX_free(ssl_ctx);
close(tunnel_fd);
send_http_error(client_fd, 502, "Bad Gateway");
continue;
}
}
// Send HTTP request to wsssht daemon
int send_result;
if (use_ssl) {
send_result = SSL_write(tunnel_ssl, request, bytes_read);
} else {
send_result = send(tunnel_fd, request, bytes_read, 0);
}
if (send_result != bytes_read) {
if (tunnel_ssl) {
SSL_shutdown(tunnel_ssl);
SSL_free(tunnel_ssl);
}
if (ssl_ctx) SSL_CTX_free(ssl_ctx);
close(tunnel_fd);
send_http_error(client_fd, 502, "Bad Gateway");
return -1;
}
// Read response from wsssht daemon and forward to client
char buffer[8192];
ssize_t total_sent = 0;
fd_set read_fds;
struct timeval tv;
while (1) {
FD_ZERO(&read_fds);
FD_SET(tunnel_fd, &read_fds);
tv.tv_sec = 10; // 10 second timeout
tv.tv_usec = 0;
// Read response from wsssht daemon and forward to client
char buffer[8192];
ssize_t total_sent = 0;
fd_set read_fds;
struct timeval tv;
while (1) {
FD_ZERO(&read_fds);
FD_SET(tunnel_fd, &read_fds);
tv.tv_sec = 10; // 10 second timeout
tv.tv_usec = 0;
int activity = select(tunnel_fd + 1, &read_fds, NULL, NULL, &tv);
if (activity < 0) {
if (errno == EINTR) continue;
break;
}
if (activity == 0) {
// Timeout
printf("[WEB-PROXY] Timeout waiting for response from wsssht\n");
break;
}
int activity = select(tunnel_fd + 1, &read_fds, NULL, NULL, &tv);
if (activity < 0) {
if (errno == EINTR) continue;
break;
}
if (activity == 0) {
// Timeout
printf("[WEB-PROXY] Timeout waiting for response from wsssht\n");
break;
}
ssize_t bytes_recv;
if (use_ssl) {
bytes_recv = SSL_read(tunnel_ssl, buffer, sizeof(buffer));
} else {
bytes_recv = recv(tunnel_fd, buffer, sizeof(buffer), 0);
}
if (bytes_recv <= 0) {
break;
}
ssize_t bytes_recv;
if (use_ssl) {
bytes_recv = SSL_read(tunnel_ssl, buffer, sizeof(buffer));
} else {
bytes_recv = recv(tunnel_fd, buffer, sizeof(buffer), 0);
}
if (bytes_recv <= 0) {
break;
ssize_t sent = send(client_fd, buffer, bytes_recv, 0);
if (sent != bytes_recv) {
break;
}
total_sent += sent;
}
ssize_t sent = send(client_fd, buffer, bytes_recv, 0);
if (sent != bytes_recv) {
break;
// Cleanup SSL
if (tunnel_ssl) {
SSL_shutdown(tunnel_ssl);
SSL_free(tunnel_ssl);
}
total_sent += sent;
}
if (ssl_ctx) SSL_CTX_free(ssl_ctx);
close(tunnel_fd);
// Cleanup SSL
if (tunnel_ssl) {
SSL_shutdown(tunnel_ssl);
SSL_free(tunnel_ssl);
printf("[WEB-PROXY] Request handled for %s (%zd bytes sent)\n", hostname, total_sent);
}
if (ssl_ctx) SSL_CTX_free(ssl_ctx);
close(tunnel_fd);
printf("[WEB-PROXY] Request handled for %s (%zd bytes sent)\n", hostname, total_sent);
return 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment