ESP32 WebServer Library -hasHeader()

Home / References / ESP32 Library / WebServer Library

Description

The hasHeader() method is used to check if a specific HTTP request header exists in the request received by the ESP32 WebServer. This method provides a boolean response indicating whether a particular header was sent by the client. It’s particularly useful for implementing conditional logic based on the presence of headers before attempting to access their values. The method checks headers that have been previously configured for collection using collectHeaders() or collectAllHeaders() methods. This is essential for creating robust web applications that need to verify the existence of authentication tokens, content types, custom headers, or any other HTTP headers before processing them.


Syntax and Usage

The hasHeader() method has a simple usage pattern:

  • Check header existence: server.hasHeader(headerName) – Returns true if the specified header exists in the current request, false otherwise. The header name is case-insensitive.

Arguments

  • headerName (String) – The name of the HTTP header to check for. This is case-insensitive, so “Content-Type”, “content-type”, and “CONTENT-TYPE” will all match the same header. The header must have been configured for collection beforehand.

Return Value

The hasHeader() method returns a boolean value: true if the specified header exists in the current request, or false if the header is not present or was not configured for collection.


Example Codes

Example 1: Basic Header Existence Check

This example demonstrates the fundamental usage of hasHeader() to check for common HTTP headers before accessing their values, preventing empty string returns.

How to use this example: Upload this code to your ESP32 and replace the WiFi credentials. After connecting, visit the ESP32’s IP address in your browser. The server will display which common headers are present or missing. Test with different clients: browsers, curl commands like curl -H "Authorization: Bearer token123" http://ESP32_IP, or mobile apps to see how header presence varies.

/*
 * Author: Avant Maker
 * Date: June 16, 2025
 * Version: 1.0
 * License: MIT 
 * 
 * Description: 
 * This example demonstrates the fundamental usage of hasHeader() to
 * check for common HTTP headers before accessing their values,
 * preventing empty string returns.
 * 
 * How to use this example: 
 * Upload this code to your ESP32 and replace the WiFi credentials.
 * After connecting, visit the ESP32's IP address in your browser.
 * The server will display which common headers are present or missing.
 * Test with different clients: browsers, curl commands like
 * curl -H "Authorization: Bearer token123" http://ESP32_IP,
 * or mobile apps to see how header presence varies.
 *
 * Code Source:
 * This example code is sourced from the Comprehensive Guide
 * to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
 * For additional code examples and in-depth documentation related to
 * the ESP32 Arduino Core Library, please visit:
 *
 * https://avantmaker.com/home/all-about-esp32-arduino-core-library/
 *
 * AvantMaker.com, your premier destination for all things
 * DIY, AI, IoT, Smart Home, and STEM projects. We are dedicated
 * to empowering makers, learners, and enthusiasts with
 * the resources they need to bring their nnovative ideas to life.
 */
 

#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";

WebServer server(80);

void handleRoot() {
  String message = "AvantMaker ESP32 Header Existence Check\n";
  message += "=============================\n\n";
  
  // Check for common headers and display results
  message += "Header Presence Report:\n";
  message += "-----------------------\n";
  
  if (server.hasHeader("User-Agent")) {
    message += "User-Agent: Present (" + server.header("User-Agent") + ")\n";
  } else {
    message += "User-Agent: Not present\n";
  }
  
  if (server.hasHeader("Accept")) {
    message += "Accept: Present (" + server.header("Accept") + ")\n";
  } else {
    message += "Accept: Not present\n";
  }
  
  if (server.hasHeader("Authorization")) {
    message += "Authorization: Present (value hidden for security)\n";
  } else {
    message += "Authorization: Not present\n";
  }
  
  if (server.hasHeader("Content-Type")) {
    message += "Content-Type: Present (" + server.header("Content-Type") + ")\n";
  } else {
    message += "Content-Type: Not present\n";
  }
  
  if (server.hasHeader("Host")) {
    message += "Host: Present (" + server.header("Host") + ")\n";
  } else {
    message += "Host: Not present\n";
  }
  
  if (server.hasHeader("Referer")) {
    message += "Referer: Present (" + server.header("Referer") + ")\n";
  } else {
    message += "Referer: Not present\n";
  }
  
  // Display total header count
  message += "\nTotal headers collected: " + String(server.headers()) + "\n";
  
  server.send(200, "text/plain", message);
}

void setup() {
  Serial.begin(115200);
  
  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  
  // Collect all headers to demonstrate hasHeader() functionality
  server.collectAllHeaders();
  
  // Set up route handler
  server.on("/", handleRoot);
  
  // Start server
  server.begin();
  Serial.println("HTTP server started");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  server.handleClient();
}

Example 2: Conditional Processing Based on Header Presence

This example shows how to use hasHeader() to implement conditional logic, handling different scenarios based on which headers are present in the request.

How to use this example: After uploading and connecting to WiFi, test different endpoints with various header combinations. Try: curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' http://ESP32_IP/data for JSON processing, curl -H "X-API-Key: secret123" http://ESP32_IP/api for API access, or visit the root page with different browsers to see user agent detection in action.

/*
 * Author: Avant Maker
 * Date: June 16, 2025
 * Version: 1.0
 * License: MIT 
 * 
 * Description: 
 * This example shows how to use hasHeader() to implement
 * conditional logic, handling different scenarios based
 * on which headers are present in the request.
 * 
 * How to use this example: 
 * After uploading and connecting to WiFi, test different endpoints
 * with various header combinations. Try: 
 * curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' http://ESP32_IP/data for JSON processing, 
 * curl -H "X-API-Key: secret123" http://ESP32_IP/api 
 * for API access, or visit the root page with different browsers to see user agent detection in action.
 *
 * Code Source:
 * This example code is sourced from the Comprehensive Guide
 * to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
 * For additional code examples and in-depth documentation related to
 * the ESP32 Arduino Core Library, please visit:
 *
 * https://avantmaker.com/home/all-about-esp32-arduino-core-library/
 *
 * AvantMaker.com, your premier destination for all things
 * DIY, AI, IoT, Smart Home, and STEM projects. We are dedicated
 * to empowering makers, learners, and enthusiasts with
 * the resources they need to bring their nnovative ideas to life.
 */
#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";

WebServer server(80);

const String validApiKey = "secret123";

void handleData() {
  String response = "";
  
  // Check if this is a POST request with content
  if (server.method() == HTTP_POST) {
    if (server.hasHeader("Content-Type")) {
      String contentType = server.header("Content-Type");
      
      if (contentType.indexOf("application/json") != -1) {
        response = "Processing JSON data...\n";
        response += "Content-Type: " + contentType + "\n";
        response += "Content received and processed as JSON\n";
      } else if (contentType.indexOf("application/x-www-form-urlencoded") != -1) {
        response = "Processing form data...\n";
        response += "Content-Type: " + contentType + "\n";
        response += "Form data received and processed\n";
      } else {
        response = "Unsupported content type: " + contentType + "\n";
        server.send(415, "text/plain", response);
        return;
      }
    } else {
      response = "Error: Content-Type header missing for POST request\n";
      server.send(400, "text/plain", response);
      return;
    }
  } else {
    response = "This endpoint expects POST requests with data\n";
    response += "Send POST request with Content-Type header\n";
  }
  
  server.send(200, "text/plain", response);
}

void handleAPI() {
  String response = "";
  
  // Check for API key authentication
  if (server.hasHeader("X-API-Key")) {
    String apiKey = server.header("X-API-Key");
    
    if (apiKey == validApiKey) {
      response = "API Access Granted\n";
      response += "===================\n\n";
      
      // Provide additional info if User-Agent is present
      if (server.hasHeader("User-Agent")) {
        response += "Client: " + server.header("User-Agent") + "\n";
      }
      
      response += "API Key: Valid\n";
      response += "Access Level: Full\n";
      response += "Request Time: " + String(millis()) + " ms\n";
      
      server.send(200, "text/plain", response);
    } else {
      server.send(403, "text/plain", "Invalid API key");
    }
  } else {
    response = "API Key Required\n";
    response += "================\n\n";
    response += "Please include X-API-Key header in your request\n";
    response += "Example: curl -H 'X-API-Key: your_key' http://ESP32_IP/api\n";
    
    server.send(401, "text/plain", response);
  }
}

void handleRoot() {
  String html = "<html><body>";
  html += "<h1>AvantMaker ESP32 Conditional Header Processing</h1>";
  
  // Customize greeting based on browser detection
  if (server.hasHeader("User-Agent")) {
    String userAgent = server.header("User-Agent");
    
    if (userAgent.indexOf("Chrome") != -1) {
      html += "<p>👋 Hello Chrome user!</p>";
    } else if (userAgent.indexOf("Firefox") != -1) {
      html += "<p>🦊 Hello Firefox user!</p>";
    } else if (userAgent.indexOf("Safari") != -1) {
      html += "<p>🧭 Hello Safari user!</p>";
    } else if (userAgent.indexOf("Edge") != -1) {
      html += "<p>🌊 Hello Edge user!</p>";
    } else {
      html += "<p>🤖 Hello there, interesting browser!</p>";
    }
  } else {
    html += "<p>👤 Hello anonymous visitor!</p>";
  }
  
  html += "<h2>Available Endpoints:</h2>";
  html += "<ul>";
  html += "<li><a href='/api'>/api</a> - API endpoint (requires X-API-Key header)</li>";
  html += "<li>/data - Data processing endpoint (requires POST with Content-Type)</li>";
  html += "</ul>";
  
  // Show referrer if present
  if (server.hasHeader("Referer")) {
    html += "<p><small>Referred from: " + server.header("Referer") + "</small></p>";
  }
  
  html += "</body></html>";
  
  server.send(200, "text/html", html);
}

void setup() {
  Serial.begin(115200);
  
  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  
  // Collect specific headers needed for our functionality
  const char* requiredHeaders[] = {"User-Agent", "Content-Type", "X-API-Key", "Referer", "Authorization"};
  const size_t headerCount = sizeof(requiredHeaders) / sizeof(requiredHeaders[0]);
  
  server.collectHeaders(requiredHeaders, headerCount);
  
  // Set up route handlers
  server.on("/", handleRoot);
  server.on("/api", handleAPI);
  server.on("/data", HTTP_POST, handleData);
  
  // Start server
  server.begin();
  Serial.println("HTTP server started");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  server.handleClient();
}

Example 3: Security Headers Validation and Request Analysis

This example demonstrates advanced usage of hasHeader() for implementing security checks, request validation, and comprehensive header analysis for monitoring purposes.

How to use this example: This creates a security-focused server that validates requests based on header presence. Test various scenarios: curl -H "X-Forwarded-For: 192.168.1.100" http://ESP32_IP/secure for proxy detection, curl -H "Origin: https://trusted-site.com" http://ESP32_IP/secure for CORS validation, or curl -H "X-Real-IP: 10.0.0.1" -H "User-Agent: SecurityBot" http://ESP32_IP/secure for multiple security header analysis. Check Serial Monitor for detailed security logs.

/*
 * Author: Avant Maker
 * Date: June 16, 2025
 * Version: 1.0
 * License: MIT 
 * 
 * Description: 
 * This example demonstrates advanced usage of hasHeader()
 * for implementing security checks, request validation,
 * and comprehensive header analysis for monitoring purposes.
 * 
 * How to use this example: 
 * This creates a security-focused server that validates
 * requests based on header presence. 
 *
 * Test for proxy detection:
 * curl -H "X-Forwarded-For: 192.168.1.100" http://ESP32_IP/secure
 * 
 * Test for CORS validation:
 * curl -H "Origin: https://trusted-site.com" http://ESP32_IP/secure
 *
 * Test for multiple security header analysis:
 * curl -H "X-Real-IP: 10.0.0.1" -H "User-Agent: SecurityBot" http://ESP32_IP/secure
 *
 * Code Source:
 * This example code is sourced from the Comprehensive Guide
 * to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
 * For additional code examples and in-depth documentation related to
 * the ESP32 Arduino Core Library, please visit:
 *
 * https://avantmaker.com/home/all-about-esp32-arduino-core-library/
 *
 * AvantMaker.com, your premier destination for all things
 * DIY, AI, IoT, Smart Home, and STEM projects. We are dedicated
 * to empowering makers, learners, and enthusiasts with
 * the resources they need to bring their nnovative ideas to life.
 */

 #include <WiFi.h>
#include <WebServer.h>

const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";

WebServer server(80);

// Trusted domains for CORS validation
const String trustedDomains[] = {"https://avantmaker.com", "https://localhost", "https://trusted-site.com"};
const size_t trustedDomainCount = sizeof(trustedDomains) / sizeof(trustedDomains[0]);

bool isTrustedOrigin(const String &origin) {
  for (size_t i = 0; i < trustedDomainCount; i++) {
    if (origin.indexOf(trustedDomains[i]) == 0) {
      return true;
    }
  }
  return false;
}

void logSecurityEvent(const String &event, const String &details) {
  Serial.println("=== SECURITY LOG ===");
  Serial.print("Timestamp: ");
  Serial.println(millis());
  Serial.print("Event: ");
  Serial.println(event);
  Serial.print("Details: ");
  Serial.println(details);
  Serial.print("Client IP: ");
  Serial.println(server.client().remoteIP());
  Serial.println("===================");
}

void handleSecure() {
  String response = "Security Analysis Report\n";
  response += "========================\n\n";
  
  bool hasSecurityIssues = false;
  String securityWarnings = "";
  
  // Check for proxy headers (potential security concern)
  if (server.hasHeader("X-Forwarded-For")) {
    String forwardedFor = server.header("X-Forwarded-For");
    response += "⚠️  Proxy detected: X-Forwarded-For = " + forwardedFor + "\n";
    logSecurityEvent("PROXY_DETECTED", "X-Forwarded-For: " + forwardedFor);
    hasSecurityIssues = true;
  }
  
  if (server.hasHeader("X-Real-IP")) {
    String realIP = server.header("X-Real-IP");
    response += "⚠️  Real IP header: X-Real-IP = " + realIP + "\n";
    logSecurityEvent("REAL_IP_HEADER", "X-Real-IP: " + realIP);
    hasSecurityIssues = true;
  }
  
  // CORS Origin validation
  if (server.hasHeader("Origin")) {
    String origin = server.header("Origin");
    if (isTrustedOrigin(origin)) {
      response += "✅ Origin validated: " + origin + "\n";
    } else {
      response += "❌ Untrusted origin: " + origin + "\n";
      logSecurityEvent("UNTRUSTED_ORIGIN", origin);
      hasSecurityIssues = true;
    }
  } else {
    response += "ℹ️  No Origin header (direct access)\n";
  }
  
  // User-Agent analysis
  if (server.hasHeader("User-Agent")) {
    String userAgent = server.header("User-Agent");
    response += "🔍 User-Agent: " + userAgent + "\n";
    
    // Check for suspicious user agents
    if (userAgent.indexOf("bot") != -1 || userAgent.indexOf("crawler") != -1 || 
        userAgent.indexOf("scanner") != -1 || userAgent.indexOf("hack") != -1) {
      response += "⚠️  Suspicious user agent detected!\n";
      logSecurityEvent("SUSPICIOUS_USER_AGENT", userAgent);
      hasSecurityIssues = true;
    }
  } else {
    response += "⚠️  No User-Agent header (suspicious)\n";
    logSecurityEvent("MISSING_USER_AGENT", "No User-Agent header present");
    hasSecurityIssues = true;
  }
  
  // Check for authentication headers
  if (server.hasHeader("Authorization")) {
    response += "🔐 Authorization header present\n";
  } else {
    response += "❌ No authorization provided\n";
  }
  
  // Check for custom security headers
  if (server.hasHeader("X-Requested-With")) {
    response += "📱 AJAX request detected\n";
  }
  
  if (server.hasHeader("Sec-Fetch-Site")) {
    String fetchSite = server.header("Sec-Fetch-Site");
    response += "🌐 Fetch site: " + fetchSite + "\n";
  }
  
  // Final security assessment
  response += "\n" + String(hasSecurityIssues ? "🚨" : "") + " Security Status: ";
  response += hasSecurityIssues ? "Issues detected" : "Clean";
  response += "\n";
  
  // Recommendation
  if (hasSecurityIssues) {
    response += "\n⚠️  Recommendation: Review security logs for details\n";
  } else {
    response += "\n✅ Recommendation: Request appears legitimate\n";
  }
  
  server.send(200, "text/plain", response);
}

void handleStats() {
  String response = "Header Statistics\n";
  response += "=================\n\n";
  
  int totalHeaders = server.headers();
  int securityHeaders = 0;
  int standardHeaders = 0;
  int customHeaders = 0;
  
  response += "Header Presence Analysis:\n";
  response += "-------------------------\n";
  
  // Standard headers
  String standardHeaderNames[] = {"Host", "User-Agent", "Accept", "Accept-Language", 
                                 "Accept-Encoding", "Connection", "Referer"};
  
  for (size_t i = 0; i < 7; i++) {
    if (server.hasHeader(standardHeaderNames[i])) {
      response += "" + standardHeaderNames[i] + "\n";
      standardHeaders++;
    }
  }
  
  // Security-related headers
  String securityHeaderNames[] = {"Authorization", "Origin", "X-Forwarded-For", 
                                 "X-Real-IP", "Sec-Fetch-Site", "X-Requested-With"};
  
  response += "\nSecurity Headers:\n";
  for (size_t i = 0; i < 6; i++) {
    if (server.hasHeader(securityHeaderNames[i])) {
      response += "🔒 " + securityHeaderNames[i] + "\n";
      securityHeaders++;
    }
  }
  
  response += "\nSummary:\n";
  response += "--------\n";
  response += "Total headers: " + String(totalHeaders) + "\n";
  response += "Standard headers: " + String(standardHeaders) + "\n";
  response += "Security headers: " + String(securityHeaders) + "\n";
  response += "Custom headers: " + String(totalHeaders - standardHeaders - securityHeaders) + "\n";
  
  server.send(200, "text/plain", response);
}

void handleRoot() {
  String html = "<html><body>";
  html += "<h1>ESP32 Security Header Monitor</h1>";
  html += "<p>Advanced header validation and security analysis system.</p>";
  html += "<h2>Endpoints:</h2>";
  html += "<ul>";
  html += "<li><a href='/secure'>/secure</a> - Security analysis with header validation</li>";
  html += "<li><a href='/stats'>/stats</a> - Header presence statistics</li>";
  html += "</ul>";
  html += "<p><strong>Note:</strong> Security events are logged to Serial Monitor.</p>";
  
  // Show current client info
  if (server.hasHeader("User-Agent")) {
    html += "<p><em>Your browser: " + server.header("User-Agent") + "</em></p>";
  }
  
  html += "</body></html>";
  
  server.send(200, "text/html", html);
}

void setup() {
  Serial.begin(115200);
  
  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  
  // Collect all headers for comprehensive security analysis
  server.collectAllHeaders();
  
  // Set up route handlers
  server.on("/", handleRoot);
  server.on("/secure", handleSecure);
  server.on("/stats", handleStats);
  
  // Start server
  server.begin();
  Serial.println("HTTP server started");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println("Security monitoring active - check Serial Monitor for security logs");
}

void loop() {
  server.handleClient();
}
error: Content is protected !!