Skip to content

mod_WebObjects sending an additional empty Host header to application #1035

@hugithordarson

Description

@hugithordarson

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());
                  }
              }
          }
      }
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions