libmicrohttpd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [libmicrohttpd] size MHD_SIZE_UNKNOWN should never be returned in he


From: Brecht Sanders
Subject: Re: [libmicrohttpd] size MHD_SIZE_UNKNOWN should never be returned in header
Date: Thu, 01 Apr 2010 13:52:55 +0200
User-agent: Thunderbird 2.0.0.24 (Windows/20100228)

Hello Christian,
Thanks for the quick response.
I looked in my code to make sure I wasn't missing anything.
Can you tell me if the MHD_ContentReaderCallback function needs to return 0 or -1 on end of data?

Then I wrote the attached test program in order to have a testcase.
On Windows (32-bit, compiled with MinGW) it returns:

    HTTP/1.1 200 OK
    Content-Length: 4294967295
    Content-Type: text/plain
    Date: Thu, 01 Apr 2010 11:42:52 GMT
   
    Hello world!

Then I ran it on 32-bit Linux (Debian Lenny 5.0.3) and I got:

    HTTP/1.1 200 OK
    Transfer-Encoding: chunked
    Content-Type: text/plain
    Date: Thu, 01 Apr 2010 11:48:41 GMT
   
    Hello world!

So there is definitely a difference: not only Content-Length is returned but also Transfer-Encoding: chunked is missing.
Or is this due to Debian being on an older version of libmicrohttpd (0.3.1-1)?

I hope this helps in finding the source of the problem.
Regards
    Brecht

Christian Grothoff wrote:
Hi!

I've looked all over the code and I cannot find any size_t/uint64_t confusion 
that would explain this.  If you were using MHD_SIZE_UNKNOWN in conjunction 
with "MHD_create_response_from_data", bad things would happen (since that's 
not allowed by the API), but other than that I cannot see how this could be:
"total_size" is set ONLY in the "create_response_from_callback" and then 
compared directly with MHD_SIZE_UNKNOWN.  

If you have a testcase (not with IE but using libcurl as a client) that checks 
for this and can reproduce it (at least on 32-bit archs), that would be very 
helpful.   As it stands, I cannot reproduce this -- and your patch, as you 
mention, is certainly rather unclean (and would break 4 GB -1byte transfers).

Happy hacking!

Christian

On Thursday 01 April 2010 10:15:09 am Brecht Sanders wrote:
  
Hi,
I use libmicrohttpd on Windows (compiled under MSYS/MinGW).
I have been looking at why my dynamic pages (using
MHD_create_response_from_callback) would not display on Internet
Explorer (version 6) while they were fine on  Firefox.
Finally I found it: the header returned includes:
    Content-Length: 4294967295
This is 0xFFFFFFFF.
In the code I see:
    #define MHD_SIZE_UNKNOWN  ((uint64_t) -1LL)
which probably corresponds, assuming you use uint64_t for size
everywhere and don't mix with size_t.
My first thought to fix this was to not return the length if it is
MHD_SIZE_UNKNOWN.
However, on my platform the (MHD_SIZE_UNKNOWN !=
connection->response->total_size) comparison didn't seem to match.
I worked around it for now with the patch below using size_t typecasts.
However I suspect an underlying problem where size gets truncated from
uint64_t to a smaller type (maybe size_t) somewhere else.
So my patch is not the perfect fix in case you will have file larger
than 4G.
Regards
    Brecht Sanders


patch -ulb src/daemon/connection.c << EOF
--- src/daemon/connection.c  2010-03-11 13:34:20 +0100
+++ src/daemon/connection.c  2010-04-01 10:02:50 +0200
@@ -498,4 +498,5 @@
     }
-  else if (NULL == MHD_get_response_header (connection->response,
-
MHD_HTTP_HEADER_CONTENT_LENGTH))
+  else if ((NULL == MHD_get_response_header (connection->response,
+
MHD_HTTP_HEADER_CONTENT_LENGTH)) &&
+           ((size_t)MHD_SIZE_UNKNOWN !=
(size_t)connection->response->total_size))
     {
EOF

    

  

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#ifdef __WIN32__
  #include <ws2tcpip.h>
#endif
#include <microhttpd.h>
#include <curl/curl.h>

#define HTTP_PORT 8000
#define HTTP_URL "http://127.0.0.1:8000/";

#if MHD_VERSION < 0x00040000
int content_read_callback (void* cls, size_t pos, char* buf, int max)
#else
int content_read_callback (void* cls, uint64_t pos, char* buf, int max)
#endif
{
  const char* body = (char*)cls;
  size_t bodylen = strlen(body);
  if (pos >= bodylen)
    return -1;
  size_t len = ((size_t)max <= bodylen - pos ? max : bodylen - pos);
  memcpy(buf, body, len);
  return len;
}

void content_free_callback (void *cls)
{
}

int on_request_data (void *cls, struct MHD_Connection *connection, const char 
*url, const char *method, const char *version, const char *upload_data, 
unsigned int *upload_data_size, void **con_cls)
{
        //on first call create data structure
        struct MHD_Response* response = NULL;
        unsigned int status_code = MHD_HTTP_OK;
  //create response
  const char* body = "Hello world!\n";
        response = MHD_create_response_from_callback((size_t)-1, 2048, 
content_read_callback, (void*)body, content_free_callback);
        if (!response) {
                status_code = MHD_HTTP_NOT_FOUND;
                response = MHD_create_response_from_data(9, (void*)"Not found", 
MHD_NO, MHD_NO);
                MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, 
"text/html");
        }
        //add header
  MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/plain");
        //send response
        int ret = MHD_queue_response(connection, status_code, response);
        MHD_destroy_response(response);
        return ret;
}

void on_request_completed (void* cls, struct MHD_Connection* connection, void** 
con_cls, enum MHD_RequestTerminationCode toe)
{
}

int main (int argc, char *const *argv)
{
  //start HTTP server
  struct MHD_Daemon* webserver;
  if ((webserver = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION | 
MHD_USE_DEBUG | MHD_USE_PEDANTIC_CHECKS, HTTP_PORT, NULL, NULL, 
&on_request_data, NULL, MHD_OPTION_NOTIFY_COMPLETED, on_request_completed, 
NULL, MHD_OPTION_END)) == NULL) {
                fprintf(stderr, "Error starting webserver on port %i\n", 
(int)HTTP_PORT);
    return 1;
  }
  //HTTP client
  CURL *curl;
  CURLcode res;
  if ((curl = curl_easy_init()) != NULL) {
    curl_easy_setopt(curl, CURLOPT_URL, HTTP_URL);
    //curl_easy_setopt(curl, CURLOPT_HTTPHEADER, 1L);
    curl_easy_setopt(curl, CURLOPT_WRITEHEADER, stdout);
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
  //stop HTTP server
  MHD_stop_daemon(webserver);
  return 0;
}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]