-
Notifications
You must be signed in to change notification settings - Fork 166
Description
When a WO application receives request from mod_WebObjects it seems there's an empty Host header in the request, in addition to the actual correctly set Host header.
When using ProxyPass this additional header is not present, so it certainly seems the problem originates with mod_WebObjects.
I think this commit might be the culprit: 983f439
The problem isn't immediately apparent since it seems WO itself (the adaptor) filters out the empty additional header before handling the request (at least I don't see it once the request has reached WOApplication.dispatchRequest() ). However, this becomes a problem when writing one's own adaptor since this goes against the HTTP spec and thus causes errors with proper HTTP server implementations. From the RFC:
A server MUST respond with a 400 (Bad Request) status code to any HTTP/1.1 request message that lacks a Host header field and to any request message that contains more than one Host header field
Request sent from mod_WebObjects
============================================================
Request: GET /Apps/WebObjects/NBAdmin.woa/1 HTTP/1.1
============================================================
All Headers:
Host: admin.netbokhald.is
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:147.0) Gecko/20100101 Firefox/147.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-GB,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
connection: close
Cookie: [removed]
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Priority: u=0, i
SCRIPT_URL: /
SCRIPT_URI: https://admin.netbokhald.is/
HTTPS: on
SSL_TLS_SNI: admin.netbokhald.is
mod_rewrite_rewritten: 1
ssl-secure-reneg: 0
SERVER_SOFTWARE: Apache/2.4.65 (Debian)
SERVER_NAME: admin.netbokhald.is
SERVER_PORT: 443
REMOTE_HOST: 31.209.136.250
REMOTE_ADDR: 31.209.136.250
DOCUMENT_ROOT: /rebbi/is.netbokhald.admin/html
SERVER_ADMIN: [no address given]
SCRIPT_FILENAME: /Apps
REMOTE_PORT: 62346
x-webobjects-adaptor-version: Apache
x-webobjects-request-method: GET
Host:
x-webobjects-request-id: 6916e73f002eaa2300000012
*** WARNING: Found 2 Host headers! ***
Host #1: 'admin.netbokhald.is'
Host #2: ''
============================================================
Request sent by mod_Proxy
============================================================
Request: GET /Apps/WebObjects/NBAdmin.woa HTTP/1.1
============================================================
All Headers:
Host: admin.netbokhald.is
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:147.0) Gecko/20100101 Firefox/147.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-GB,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
Cookie: [removed]
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Priority: u=0, i
X-Forwarded-For: 31.209.136.250
X-Forwarded-Host: admin.netbokhald.is
X-Forwarded-Server: admin.netbokhald.is
Connection: Keep-Alive
============================================================
Code used for inspecting the request:
import java.io.*;
import java.net.*;
import java.util.*;
public class DebugServer {
public static void main(String[] args) throws IOException {
int port = args.length > 0 ? Integer.parseInt(args[0]) : 1200;
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("Debug HTTP server listening on port " + port);
System.out.println("Ctrl+C to stop\n");
while (true) {
try (Socket clientSocket = serverSocket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream())) {
System.out.println("============================================================");
// Read request line
String requestLine = in.readLine();
System.out.println("Request: " + requestLine);
System.out.println("============================================================");
// Read headers
System.out.println("\nAll Headers:");
Map<String, List<String>> headers = new LinkedHashMap<>();
String line;
while ((line = in.readLine()) != null && !line.isEmpty()) {
int colonIndex = line.indexOf(':');
if (colonIndex > 0) {
String headerName = line.substring(0, colonIndex).trim();
String headerValue = line.substring(colonIndex + 1).trim();
headers.computeIfAbsent(headerName, k -> new ArrayList<>()).add(headerValue);
System.out.println(" " + headerName + ": " + headerValue);
}
}
// Check for duplicate Host headers
List<String> hostHeaders = headers.get("Host");
if (hostHeaders != null && hostHeaders.size() > 1) {
System.out.println("\n*** WARNING: Found " + hostHeaders.size() + " Host headers! ***");
for (int i = 0; i < hostHeaders.size(); i++) {
System.out.println(" Host #" + (i+1) + ": '" + hostHeaders.get(i) + "'");
}
} else if (hostHeaders != null && hostHeaders.size() == 1 && hostHeaders.get(0).isEmpty()) {
System.out.println("\n*** WARNING: Host header is EMPTY! ***");
}
System.out.println("============================================================\n");
// Send simple response
out.println("HTTP/1.1 200 OK");
out.println("Content-Type: text/plain");
out.println("Content-Length: 32");
out.println();
out.println("Debug server received request");
out.flush();
} catch (IOException e) {
System.err.println("Error handling request: " + e.getMessage());
}
}
}
}
}