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) { ...@@ -389,288 +389,297 @@ static void *proxy_data_forward(void *arg) {
// Handle incoming HTTP request by proxying to wsssht daemon // 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) { static int handle_proxy_request(int client_fd, wssshd_state_t *state, const wssshd_config_t *config) {
char request[8192]; // Find client once, assume all requests on this connection are for the same hostname
ssize_t bytes_read = recv(client_fd, request, sizeof(request) - 1, 0); char first_hostname[256] = {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
client_t *client = NULL; client_t *client = NULL;
pthread_mutex_lock(&state->client_mutex); const char *service_type = NULL;
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;
}
}
if (hostname_match) { while (1) {
client = c; char request[8192];
ssize_t bytes_read = recv(client_fd, request, sizeof(request) - 1, 0);
if (bytes_read <= 0) {
break; break;
} }
} request[bytes_read] = '\0';
pthread_mutex_unlock(&state->client_mutex);
if (!client) { // Parse Host header
printf("[WEB-PROXY] No client found for hostname: %s\n", hostname); char hostname[256];
send_http_error(client_fd, 404, "Not Found"); if (parse_host_header(request, hostname, sizeof(hostname)) != 0) {
return -1; 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 if (hostname_match) {
bool has_web_service = false; client = c;
const char *service_type = NULL; break;
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--;
} }
pthread_mutex_unlock(&state->client_mutex);
if (strncmp(service_token, "web", 3) == 0) { if (!client) {
has_web_service = true; printf("[WEB-PROXY] No client found for hostname: %s\n", hostname);
service_type = "web"; send_http_error(client_fd, 404, "Not Found");
break; continue;
} 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;
} }
service_token = strtok(NULL, ","); printf("[WEB-PROXY] Found client: %s\n", client->client_id);
}
free(services_copy); // 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) { if (strncmp(service_token, "web", 3) == 0) {
printf("[WEB-PROXY] Client %s does not have web/http/https services\n", client->client_id); has_web_service = true;
send_http_error(client_fd, 503, "Service Unavailable"); service_type = "web";
return -1; 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 service_token = strtok(NULL, ",");
bool use_ssl = false; }
if (strcmp(service_type, "https") == 0) { free(services_copy);
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);
}
// Find or create wsssht process if (!has_web_service) {
wsssht_process_t *proc = find_or_create_wsssht_process(hostname, service_type, client->client_id, config->domain); printf("[WEB-PROXY] Client %s does not have web/http/https services\n", client->client_id);
if (!proc) { send_http_error(client_fd, 503, "Service Unavailable");
printf("[WEB-PROXY] Failed to launch wsssht daemon for %s\n", hostname); continue;
send_http_error(client_fd, 502, "Bad Gateway"); }
return -1; }
}
// Connect to wsssht daemon // Determine if SSL should be used
int tunnel_fd = socket(AF_INET, SOCK_STREAM, 0); bool use_ssl = false;
if (tunnel_fd < 0) { if (strcmp(service_type, "https") == 0) {
perror("[WEB-PROXY] Failed to create socket"); use_ssl = true;
send_http_error(client_fd, 500, "Internal Server Error"); printf("[WEB-PROXY] Service type 'https', using SSL\n");
return -1; } 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; // Find or create wsssht process
memset(&addr, 0, sizeof(addr)); wsssht_process_t *proc = find_or_create_wsssht_process(hostname, service_type, client->client_id, config->domain);
addr.sin_family = AF_INET; if (!proc) {
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); printf("[WEB-PROXY] Failed to launch wsssht daemon for %s\n", hostname);
addr.sin_port = htons(proc->port); send_http_error(client_fd, 502, "Bad Gateway");
continue;
}
printf("[WEB-PROXY] Connecting to wsssht on localhost:%d\n", proc->port); // Connect to wsssht daemon
if (connect(tunnel_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { int tunnel_fd = socket(AF_INET, SOCK_STREAM, 0);
perror("[WEB-PROXY] Failed to connect to wsssht"); if (tunnel_fd < 0) {
close(tunnel_fd); perror("[WEB-PROXY] Failed to create socket");
send_http_error(client_fd, 502, "Bad Gateway"); send_http_error(client_fd, 500, "Internal Server Error");
return -1; 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");
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;
while (1) { struct sockaddr_in addr;
ret = SSL_connect(tunnel_ssl); memset(&addr, 0, sizeof(addr));
if (ret > 0) { addr.sin_family = AF_INET;
printf("[WEB-PROXY] SSL connection established\n"); addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
break; 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); } else {
if (err == SSL_ERROR_WANT_READ) { // Set socket non-blocking for SSL timeout
FD_ZERO(&fdset); int flags = fcntl(tunnel_fd, F_GETFL, 0);
FD_SET(tunnel_fd, &fdset); fcntl(tunnel_fd, F_SETFL, flags | O_NONBLOCK);
int sel = select(tunnel_fd + 1, &fdset, NULL, NULL, &tv);
if (sel <= 0) { tunnel_ssl = SSL_new(ssl_ctx);
printf("[WEB-PROXY] SSL connection timeout on read\n"); SSL_set_fd(tunnel_ssl, tunnel_fd);
ret = -1;
// 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; break;
} }
} else if (err == SSL_ERROR_WANT_WRITE) { int err = SSL_get_error(tunnel_ssl, ret);
FD_ZERO(&fdset); if (err == SSL_ERROR_WANT_READ) {
FD_SET(tunnel_fd, &fdset); FD_ZERO(&fdset);
int sel = select(tunnel_fd + 1, NULL, &fdset, NULL, &tv); FD_SET(tunnel_fd, &fdset);
if (sel <= 0) { int sel = select(tunnel_fd + 1, &fdset, NULL, NULL, &tv);
printf("[WEB-PROXY] SSL connection timeout on write\n"); 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; ret = -1;
break; break;
} }
} else {
printf("[WEB-PROXY] SSL connection failed with error %d\n", err);
ret = -1;
break;
} }
}
if (ret <= 0) { if (ret <= 0) {
SSL_free(tunnel_ssl); SSL_free(tunnel_ssl);
tunnel_ssl = NULL; tunnel_ssl = NULL;
SSL_CTX_free(ssl_ctx); SSL_CTX_free(ssl_ctx);
ssl_ctx = NULL; ssl_ctx = NULL;
if (strcmp(service_type, "web") == 0) { if (strcmp(service_type, "web") == 0) {
use_ssl = false; // Fallback to HTTP use_ssl = false; // Fallback to HTTP
printf("[WEB-PROXY] Falling back to plain TCP\n"); printf("[WEB-PROXY] Falling back to plain TCP\n");
} else { } else {
close(tunnel_fd); close(tunnel_fd);
send_http_error(client_fd, 502, "Bad Gateway"); send_http_error(client_fd, 502, "Bad Gateway");
return -1; 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) { 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 // Read response from wsssht daemon and forward to client
int send_result; char buffer[8192];
if (use_ssl) { ssize_t total_sent = 0;
send_result = SSL_write(tunnel_ssl, request, bytes_read); fd_set read_fds;
} else { struct timeval tv;
send_result = send(tunnel_fd, request, bytes_read, 0); while (1) {
} FD_ZERO(&read_fds);
if (send_result != bytes_read) { FD_SET(tunnel_fd, &read_fds);
if (tunnel_ssl) { tv.tv_sec = 10; // 10 second timeout
SSL_shutdown(tunnel_ssl); tv.tv_usec = 0;
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 int activity = select(tunnel_fd + 1, &read_fds, NULL, NULL, &tv);
char buffer[8192]; if (activity < 0) {
ssize_t total_sent = 0; if (errno == EINTR) continue;
fd_set read_fds; break;
struct timeval tv; }
while (1) { if (activity == 0) {
FD_ZERO(&read_fds); // Timeout
FD_SET(tunnel_fd, &read_fds); printf("[WEB-PROXY] Timeout waiting for response from wsssht\n");
tv.tv_sec = 10; // 10 second timeout break;
tv.tv_usec = 0; }
int activity = select(tunnel_fd + 1, &read_fds, NULL, NULL, &tv); ssize_t bytes_recv;
if (activity < 0) { if (use_ssl) {
if (errno == EINTR) continue; bytes_recv = SSL_read(tunnel_ssl, buffer, sizeof(buffer));
break; } else {
} bytes_recv = recv(tunnel_fd, buffer, sizeof(buffer), 0);
if (activity == 0) { }
// Timeout if (bytes_recv <= 0) {
printf("[WEB-PROXY] Timeout waiting for response from wsssht\n"); break;
break; }
}
ssize_t bytes_recv; ssize_t sent = send(client_fd, buffer, bytes_recv, 0);
if (use_ssl) { if (sent != bytes_recv) {
bytes_recv = SSL_read(tunnel_ssl, buffer, sizeof(buffer)); break;
} else { }
bytes_recv = recv(tunnel_fd, buffer, sizeof(buffer), 0); total_sent += sent;
}
if (bytes_recv <= 0) {
break;
} }
ssize_t sent = send(client_fd, buffer, bytes_recv, 0); // Cleanup SSL
if (sent != bytes_recv) { if (tunnel_ssl) {
break; SSL_shutdown(tunnel_ssl);
SSL_free(tunnel_ssl);
} }
total_sent += sent; if (ssl_ctx) SSL_CTX_free(ssl_ctx);
} close(tunnel_fd);
// Cleanup SSL printf("[WEB-PROXY] Request handled for %s (%zd bytes sent)\n", hostname, total_sent);
if (tunnel_ssl) {
SSL_shutdown(tunnel_ssl);
SSL_free(tunnel_ssl);
} }
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; 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