/* This file is part of libmicrohttpd Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file lib/action_from_response.c * @brief implementation of #MHD_action_from_response() * @author Christian Grothoff */ #include "internal.h" #include "connection_call_handlers.h" /** * A response was given as the desired action for a @a request. * Queue the response for the request. * * @param cls the `struct MHD_Response` * @param request the request we are processing * @return #MHD_SC_OK on success */ static enum MHD_StatusCode response_action (void *cls, struct MHD_Request *request) { struct MHD_Response *response = cls; struct MHD_Daemon *daemon = request->daemon; /* If daemon was shut down in parallel, * response will be aborted now or on later stage. */ if (daemon->shutdown) return MHD_SC_DAEMON_ALREADY_SHUTDOWN; #ifdef UPGRADE_SUPPORT if ( (NULL != response->upgrade_handler) && daemon->disallow_upgrade ) { #ifdef HAVE_MESSAGES MHD_DLOG (daemon, MHD_SC_UPGRADE_ON_DAEMON_WITH_UPGRADE_DISALLOWED, _("Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n")); #endif return MHD_SC_UPGRADE_ON_DAEMON_WITH_UPGRADE_DISALLOWED; } #endif /* UPGRADE_SUPPORT */ request->response = response; #if defined(_MHD_HAVE_SENDFILE) if ( (-1 == response->fd) #if HTTPS_SUPPORT || (NULL != daemon->tls_api) #endif ) request->resp_sender = MHD_resp_sender_std; else request->resp_sender = MHD_resp_sender_sendfile; #endif /* _MHD_HAVE_SENDFILE */ if ( (MHD_METHOD_HEAD == request->method) || (MHD_HTTP_OK > response->status_code) || (MHD_HTTP_NO_CONTENT == response->status_code) || (MHD_HTTP_NOT_MODIFIED == response->status_code) ) { /* if this is a "HEAD" request, or a status code for which a body is not allowed, pretend that we have already sent the full message body. */ request->response_write_position = response->total_size; } if ( (MHD_REQUEST_HEADERS_PROCESSED == request->state) && ( (MHD_METHOD_POST == request->method) || (MHD_METHOD_PUT == request->method) ) ) { /* response was queued "early", refuse to read body / footers or further requests! */ request->connection->read_closed = true; request->state = MHD_REQUEST_FOOTERS_RECEIVED; } if (! request->in_idle) (void) MHD_request_handle_idle_ (request); return MHD_SC_OK; } /** * Converts a @a response to an action. If @a consume * is set, the reference to the @a response is consumed * by the conversion. If @a consume is #MHD_NO, then * the response can be converted to actions in the future. * However, the @a response is frozen by this step and * must no longer be modified (i.e. by setting headers). * * @param response response to convert, not NULL * @param destroy_after_use should the response object be consumed? * @return corresponding action, never returns NULL * * Implementation note: internally, this is largely just * a cast (and possibly an RC increment operation), * as a response *is* an action. As no memory is * allocated, this operation cannot fail. */ _MHD_EXTERN const struct MHD_Action * MHD_action_from_response (struct MHD_Response *response, enum MHD_Bool destroy_after_use) { response->action.action = &response_action; response->action.action_cls = response; if (! destroy_after_use) { MHD_mutex_lock_chk_ (&response->mutex); response->reference_count++; MHD_mutex_unlock_chk_ (&response->mutex); } return &response->action; } /* end of action_from_response */