View Issue Details

IDProjectCategoryView StatusLast Update
0003107libmicrohttpdexternal APIpublic2013-11-17 12:37
Reporterpwielders Assigned ToChristian Grothoff  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionwon't fix 
PlatformX86OSLinuxOS VersionUbuntu 13.04
Summary0003107: ContentReaderFreeCallback not called in case the "reference" to the response object is maintained.
DescriptionWhenever the Response object is maintained to use for several responses, the ContenteReaderFreeCallback is not called in case the ContentReaderCallback reports an END of the stream.

This makes the concept of maintaining the Response object for handling multiple objects useless.

Steps To ReproduceBuilding a C++ wrapper around the C calls:

               void SendResponse (struct MHD_Connection *connection)
                {
                    ASSERT (_state != QUEUED);

                    if (_state != HANDLED) // So, IDLE or LOADED
                    {
                        // Send the default answer!!!!
                        if (_XML == true)
                        {
                            _responseText = "<html><head><title>Error</title></head><body>Bad data</body></html>";
                        }
                        else
                        {
                            _responseText = "<html><head><title>Error</title></head><body>Bad data</body></html>";
                        }
                        _status = HTTP_FAIL;
                    }
                    _processed = 0;
                    _state = QUEUED;
                    struct MHD_Response* response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, _recommendedBlockSize, &ContentReaderCallback, this, &ContentReaderFreeCallback);
                    MHD_add_response_header(response, "Content-Type", "text");
                    MHD_queue_response (connection, _status, response);
                    MHD_destroy_response (response);
                }
                static long int ContentReaderCallback (void *cls, uint64_t pos, char *buf, size_t max)
                {
                    ASSERT (static_cast<Request*>(cls)->_state == QUEUED);

                    const string& myBuffer = (static_cast<Request*>(cls))->_responseText;

                    size_t length = myBuffer.length() - pos;

                    if (length > max)
                    {
                        length = max;
                    }

                    const char* source = &(myBuffer.data()[pos]);

                    std::cout << "Transfer: " << length << " bytes." << std::endl;
                    ::memcpy (buf, source, length);

                    return (length == 0 ? MHD_CONTENT_READER_END_OF_STREAM : length);
                }
                static void ContentReaderFreeCallback (void* cls)
                {
                    std::cout << "Completed !!" << std::endl;
                    static_cast<Request*>(cls)->_state = IDLE;
                }

The code above works fine as the Creation of the response object id one prior to the enqueu and released (destroyed) after the enqueu. If, however, this creation of the response object is moved to the constructur of the Request class and cleared in the destructor of the request class, the ContentReaderFreeCallback is never called.
Additional InformationFull source code, for C++ wrapper attached. Still in experimental phase, needs to be restructures
TagsNo tags attached.
Attached Files
restserver2.cpp (29,408 bytes)

Activities

Christian Grothoff

2013-11-17 12:37

manager   ~0007645

This is totally intentional and expected behavior: the free callback is used to allow applications to clean up after themselves, it has nothing to do with an individual client reaching the end of the stream.

If you do keep a reference to the response, you are telling MHD that you might pass the same response object for another request, and thus MHD will not invoke the cleaner callback.

Just to be clear, "free" is used to _close_ the file. If you use the same response object with multiple requests, there is NO guarantee that they will access it sequentially and so you could not use the 'clenaer' to reset the stream either. MHD might ask the response to deliver bytes 0-5, then 6-10, then AGAIN 0-5, then 11-20 and then 6-EOF and then 21-EOF. If your response object is shared with multiple connection, that is a legitimate request sequence that it must be able to handle. Thus, having a callback to the cleaner after "EOF" is useless anyway. Not to mention that if there is something you really need to do upon reaching EOF, you can simply do that within your callback at that time.

Issue History

Date Modified Username Field Change
2013-11-10 19:58 pwielders New Issue
2013-11-10 19:58 pwielders File Added: restserver2.cpp
2013-11-17 12:37 Christian Grothoff Note Added: 0007645
2013-11-17 12:37 Christian Grothoff Assigned To => Christian Grothoff
2013-11-17 12:37 Christian Grothoff Status new => assigned
2013-11-17 12:37 Christian Grothoff Status assigned => closed
2013-11-17 12:37 Christian Grothoff Resolution open => won't fix
2024-01-21 13:24 Christian Grothoff Category libmicrohttpd API => external API