View Issue Details

IDProjectCategoryView StatusLast Update
0007242libmicrohttpdHTTP 1.1 request pipeliningpublic2023-02-08 15:33
Reportergray Assigned ToChristian Grothoff  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionno change required 
Product Version0.9.75 
Target Version0.9.76Fixed in Version0.9.75 
Summary0007242: Connection: close is always set in response
DescriptionLibmicrohttpd always sets "Connection: close" header in response to HTTP/1.1 requests. In my opinion, it is wrong, as HTTP 1.1 assumes keep-alive by defauit. Correct me if I'm wrong. The header is set to "close" because MHD_queue_response sets connection->discard_request to true in line 5261 of connection.c. Apparently, this tracks down to commit 78d0fb7b2. Before that, the "Connection:" header was set to "Keep-Alive", as expected.
Steps To ReproduceAttached is a trivial program implementing a HTTP server listening on port 8080. Compile and run it. From another console, run curl -v http://127.0.0.1:8080/. You will see "Connection: close" in response.

When compiled with libmicrohttpd prior to commit 78d0fb7b2, Keep-Alive" would be returned instead.
TagsNo tags attached.
Attached Files
connclose.c (1,025 bytes)   
#include <microhttpd.h>
#include <signal.h>

static enum MHD_Result
httpd_handler (void *cls,
	       struct MHD_Connection *conn,
	       const char *url, const char *method,
	       const char *version,
	       const char *upload_data, size_t *upload_data_size,
	       void **con_cls)
{
  struct MHD_Response *response;
  enum MHD_Result ret;
  static char resp[] = "Response text";
  
  response = MHD_create_response_from_buffer (sizeof (resp) - 1, resp, MHD_RESPMEM_PERSISTENT);
  MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/plain");
  ret = MHD_queue_response (conn, MHD_HTTP_OK, response);
  MHD_destroy_response (response);
  return ret;
}

int
main (int argc, char **argv)
{
  struct MHD_Daemon *mhd;
  int port = 8080;
  sigset_t sigs;
  int i;
	
  mhd = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
			  port,
			  NULL, NULL,
			  httpd_handler, NULL,
			  MHD_OPTION_END);

  sigfillset (&sigs);
  sigwait (&sigs, &i);
  MHD_stop_daemon (mhd);
  return 0;
}
connclose.c (1,025 bytes)   

Activities

Christian Grothoff

2023-02-08 15:32

manager   ~0019782

You're using the API wrong. You MUST NOT queue the response on the first callback *unless* you intend to return an error, prevent further uploads and close the connection. Correct usage of the API is attached (minimal modification to your code). With this, I can do:

$ telnet localhost 8080
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Wed, 08 Feb 2023 14:31:31 GMT
Content-Type: text/plain
Content-Length: 13

Response textGET / HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Wed, 08 Feb 2023 14:31:41 GMT
Content-Type: text/plain
Content-Length: 13

Response text
connclose-2.c (1,295 bytes)   
#include <microhttpd.h>
#include <signal.h>

static enum MHD_Result
httpd_handler (void *cls,
               struct MHD_Connection *conn,
               const char *url, const char *method,
               const char *version,
               const char *upload_data, size_t *upload_data_size,
               void **con_cls)
{
  struct MHD_Response *response;
  enum MHD_Result ret;
  static char resp[] = "Response text";

  if (NULL == *con_cls)
  {
    *con_cls = "not null";
    return MHD_YES;
  }

  response = MHD_create_response_from_buffer (sizeof (resp) - 1, resp,
                                              MHD_RESPMEM_PERSISTENT);
  MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE,
                           "text/plain");
  ret = MHD_queue_response (conn, MHD_HTTP_OK, response);
  MHD_destroy_response (response);
  return ret;
}


int
main (int argc, char **argv)
{
  struct MHD_Daemon *mhd;
  int port = 8080;
  sigset_t sigs;
  int i;

  mhd = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
                          port,
                          NULL, NULL,
                          httpd_handler, NULL,
                          MHD_OPTION_END);

  sigfillset (&sigs);
  sigwait (&sigs, &i);
  MHD_stop_daemon (mhd);
  return 0;
}
connclose-2.c (1,295 bytes)   

Issue History

Date Modified Username Field Change
2022-05-14 14:50 gray New Issue
2022-05-14 14:50 gray File Added: connclose.c
2023-02-08 15:32 Christian Grothoff Note Added: 0019782
2023-02-08 15:32 Christian Grothoff File Added: connclose-2.c
2023-02-08 15:33 Christian Grothoff Assigned To => Christian Grothoff
2023-02-08 15:33 Christian Grothoff Status new => resolved
2023-02-08 15:33 Christian Grothoff Resolution open => no change required
2023-02-08 15:33 Christian Grothoff Fixed in Version => 0.9.75
2023-02-08 15:33 Christian Grothoff Status resolved => closed
2023-02-08 15:33 Christian Grothoff Target Version => 0.9.76