| /* |
| 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/response.c |
| * @brief implementation of general response functions |
| * @author Daniel Pittman |
| * @author Christian Grothoff |
| * @author Karlson2k (Evgeny Grin) |
| */ |
| #include "internal.h" |
| |
| |
| /** |
| * Add a header or footer line to the response. |
| * |
| * @param response response to add a header to |
| * @param kind header or footer |
| * @param header the header to add |
| * @param content value to add |
| * @return false on error (i.e. invalid header or content format). |
| */ |
| static bool |
| add_response_entry (struct MHD_Response *response, |
| enum MHD_ValueKind kind, |
| const char *header, |
| const char *content) |
| { |
| struct MHD_HTTP_Header *hdr; |
| |
| if ( (NULL == header) || |
| (NULL == content) || |
| (0 == header[0]) || |
| (0 == content[0]) || |
| (NULL != strchr (header, '\t')) || |
| (NULL != strchr (header, '\r')) || |
| (NULL != strchr (header, '\n')) || |
| (NULL != strchr (content, '\t')) || |
| (NULL != strchr (content, '\r')) || |
| (NULL != strchr (content, '\n')) ) |
| return false; |
| if (NULL == (hdr = malloc (sizeof (struct MHD_HTTP_Header)))) |
| return false; |
| if (NULL == (hdr->header = strdup (header))) |
| { |
| free (hdr); |
| return false; |
| } |
| if (NULL == (hdr->value = strdup (content))) |
| { |
| free (hdr->header); |
| free (hdr); |
| return false; |
| } |
| hdr->kind = kind; |
| hdr->next = response->first_header; |
| response->first_header = hdr; |
| return true; |
| } |
| |
| |
| /** |
| * Explicitly decrease reference counter of a response object. If the |
| * counter hits zero, destroys a response object and associated |
| * resources. Usually, this is implicitly done by converting a |
| * response to an action and returning the action to MHD. |
| * |
| * @param response response to decrement RC of |
| * @ingroup response |
| */ |
| void |
| MHD_response_queue_for_destroy (struct MHD_Response *response) |
| { |
| struct MHD_HTTP_Header *pos; |
| |
| MHD_mutex_lock_chk_ (&response->mutex); |
| if (0 != --(response->reference_count)) |
| { |
| MHD_mutex_unlock_chk_ (&response->mutex); |
| return; |
| } |
| MHD_mutex_unlock_chk_ (&response->mutex); |
| MHD_mutex_destroy_chk_ (&response->mutex); |
| if (NULL != response->crfc) |
| response->crfc (response->crc_cls); |
| while (NULL != response->first_header) |
| { |
| pos = response->first_header; |
| response->first_header = pos->next; |
| free (pos->header); |
| free (pos->value); |
| free (pos); |
| } |
| free (response); |
| } |
| |
| |
| /** |
| * Add a header line to the response. |
| * |
| * @param response response to add a header to |
| * @param header the header to add |
| * @param content value to add |
| * @return #MHD_NO on error (i.e. invalid header or content format), |
| * or out of memory |
| * @ingroup response |
| */ |
| enum MHD_Bool |
| MHD_response_add_header (struct MHD_Response *response, |
| const char *header, |
| const char *content) |
| { |
| return add_response_entry (response, |
| MHD_HEADER_KIND, |
| header, |
| content) ? MHD_YES : MHD_NO; |
| } |
| |
| |
| /** |
| * Add a tailer line to the response. |
| * |
| * @param response response to add a footer to |
| * @param footer the footer to add |
| * @param content value to add |
| * @return #MHD_NO on error (i.e. invalid footer or content format), |
| * or out of memory |
| * @ingroup response |
| */ |
| enum MHD_Bool |
| MHD_response_add_trailer (struct MHD_Response *response, |
| const char *footer, |
| const char *content) |
| { |
| return add_response_entry (response, |
| MHD_FOOTER_KIND, |
| footer, |
| content) ? MHD_YES : MHD_NO; |
| } |
| |
| |
| /** |
| * Delete a header (or footer) line from the response. |
| * |
| * @param response response to remove a header from |
| * @param header the header to delete |
| * @param content value to delete |
| * @return #MHD_NO on error (no such header known) |
| * @ingroup response |
| */ |
| enum MHD_Bool |
| MHD_response_del_header (struct MHD_Response *response, |
| const char *header, |
| const char *content) |
| { |
| struct MHD_HTTP_Header *pos; |
| struct MHD_HTTP_Header *prev; |
| |
| prev = NULL; |
| pos = response->first_header; |
| while (NULL != pos) |
| { |
| if ((0 == strcmp (header, |
| pos->header)) && |
| (0 == strcmp (content, |
| pos->value))) |
| { |
| free (pos->header); |
| free (pos->value); |
| if (NULL == prev) |
| response->first_header = pos->next; |
| else |
| prev->next = pos->next; |
| free (pos); |
| return MHD_YES; |
| } |
| prev = pos; |
| pos = pos->next; |
| } |
| return MHD_NO; |
| } |
| |
| |
| /** |
| * Get all of the headers (and footers) added to a response. |
| * |
| * @param response response to query |
| * @param iterator callback to call on each header; |
| * maybe NULL (then just count headers) |
| * @param iterator_cls extra argument to @a iterator |
| * @return number of entries iterated over |
| * @ingroup response |
| */ |
| unsigned int |
| MHD_response_get_headers (struct MHD_Response *response, |
| MHD_KeyValueIterator iterator, |
| void *iterator_cls) |
| { |
| unsigned int numHeaders = 0; |
| struct MHD_HTTP_Header *pos; |
| |
| for (pos = response->first_header; |
| NULL != pos; |
| pos = pos->next) |
| { |
| numHeaders++; |
| if ( (NULL != iterator) && |
| (MHD_YES != iterator (iterator_cls, |
| pos->kind, |
| pos->header, |
| pos->value)) ) |
| break; |
| } |
| return numHeaders; |
| } |
| |
| |
| /** |
| * Get a particular header (or footer) from the response. |
| * |
| * @param response response to query |
| * @param key which header to get |
| * @return NULL if header does not exist |
| * @ingroup response |
| */ |
| const char * |
| MHD_response_get_header (struct MHD_Response *response, |
| const char *key) |
| { |
| struct MHD_HTTP_Header *pos; |
| |
| for (pos = response->first_header; |
| NULL != pos; |
| pos = pos->next) |
| { |
| if (MHD_str_equal_caseless_ (pos->header, |
| key)) |
| return pos->value; |
| } |
| return NULL; |
| } |
| |
| |
| /* end of response.c */ |