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