aboutsummaryrefslogtreecommitdiff
path: root/src/lib/action_from_response.c
blob: 3c13cf42b7035dd19888f919a08fbc33943e4aeb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
  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"


/**
 * 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
 */
static void
response_action (void *cls,
		 struct MHD_Request *request)
{
  struct MHD_Response *response = cls;
  struct MHD_Daemon *daemon = response->daemon;

  if (daemon->shutdown)
    return MHD_YES; /* If daemon was shut down in parallel,
                     * response will be aborted now or on later stage. */

#ifdef UPGRADE_SUPPORT
  if ( (NULL != response->upgrade_handler) &&
       (0 == (daemon->options & MHD_ALLOW_UPGRADE)) )
    {
#ifdef HAVE_MESSAGES
      MHD_DLOG (daemon,
                _("Attempted 'upgrade' connection on daemon without MHD_ALLOW_UPGRADE option!\n"));
#endif
      return MHD_NO;
    }
#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 ( ( (NULL != request->method) &&
         (MHD_str_equal_caseless_ (request->method,
                                   MHD_HTTP_METHOD_HEAD)) ) ||
       (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) &&
       (NULL != connection->method) &&
       ( (MHD_str_equal_caseless_ (request->method,
                                   MHD_HTTP_METHOD_POST)) ||
	 (MHD_str_equal_caseless_ (request->method,
                                   MHD_HTTP_METHOD_PUT))) )
    {
      /* response was queued "early", refuse to read body / footers or
         further requests! */
      connection->read_closed = true;
      request->state = MHD_CONNECTION_FOOTERS_RECEIVED;
    }
  if (! request->in_idle)
    (void) MHD_connection_handle_idle (connection);
}


/**
 * 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 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 */