summaryrefslogtreecommitdiff
path: root/src/daemon/response.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/response.c')
-rw-r--r--src/daemon/response.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/src/daemon/response.c b/src/daemon/response.c
new file mode 100644
index 00000000..a26b003b
--- /dev/null
+++ b/src/daemon/response.c
@@ -0,0 +1,333 @@
+/*
+ This file is part of libmicrohttpd
+ (C) 2007 Daniel Pittman
+
+ libmicrohttpd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ libmicrohttpd 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libmicrohttpd; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file response.c
+ * @brief Methods for managing response objects
+ * @author Daniel Pittman
+ * @author Christian Grothoff
+ * @version 0.1.0
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg>
+#include <fcntl.h>
+#include <pthread.h>
+#include <netinet/in.h>
+
+#include "microhttpd.h"
+#include "response.h"
+#include "internal.h"
+#include "config.h"
+
+
+/**
+ * Representation of a response.
+ */
+struct MHD_Response {
+
+ /**
+ * Headers to send for the response. Initially
+ * the linked list is created in inverse order;
+ * the order should be inverted before sending!
+ */
+ struct MHD_HTTP_Header * first_header;
+
+ /**
+ * Buffer pointing to data that we are supposed
+ * to send as a response.
+ */
+ void * data;
+
+ /**
+ * Closure to give to the content reader
+ * free callback.
+ */
+ void * crc_cls;
+
+ /**
+ * How do we get more data? NULL if we are
+ * given all of the data up front.
+ */
+ MHD_ContentReaderCallback crc;
+
+ /**
+ * NULL if data must not be freed, otherwise
+ * either user-specified callback or "&free".
+ */
+ MHD_ContentReaderFreeCallback crfc;
+
+ /**
+ * Mutex to synchronize access to data/size and
+ * reference counts.
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * Reference count for this response. Free
+ * once the counter hits zero.
+ */
+ unsigned int reference_count;
+
+ /**
+ * Set to -1 if size is not known.
+ */
+ size_t total_size;
+
+ /**
+ * Size of data.
+ */
+ size_t data_size;
+
+ /**
+ * At what offset in the stream is the
+ * beginning of data located?
+ */
+ size_t data_start;
+
+};
+
+
+
+/**
+ * Add a header line to the response.
+ *
+ * @return MHD_NO on error (i.e. invalid header or content format).
+ */
+int
+MHD_add_response_header(struct MHD_Response * response,
+ const char * header,
+ const char * content) {
+ struct MHD_HTTP_Header * hdr;
+
+ if ( (response == NULL) ||
+ (header == NULL) ||
+ (content == NULL) ||
+ (strlen(header) == 0) ||
+ (strlen(content) == 0) ||
+ (NULL != strstr(header, "\t")) ||
+ (NULL != strstr(header, "\r")) ||
+ (NULL != strstr(header, "\n")) ||
+ (NULL != strstr(content, "\t")) ||
+ (NULL != strstr(content, "\r")) ||
+ (NULL != strstr(content, "\n")) )
+ return MHD_NO;
+ hdr = malloc(sizeof(MHD_HTTP_Header));
+ hdr->header = STRDUP(header);
+ hdr->value = STRDUP(content);
+ hdr->kind = MHD_HEADER_KIND;
+ hdr->next = response->first_header;
+ response->first_header = hdr;
+ return MHD_YES;
+}
+
+/**
+ * Delete a header line from the response.
+ *
+ * @return MHD_NO on error (no such header known)
+ */
+int
+MHD_del_response_header(struct MHD_Response * response,
+ const char * header,
+ const char * content) {
+ struct MHD_HTTP_Header * pos;
+ struct MHD_HTTP_Header * prev;
+
+ if ( (header == NULL) ||
+ (content == NULL) )
+ return MHD_NO;
+ prev = NULL;
+ pos = response->first_header;
+ while (pos != NULL) {
+ if ( (0 == strcmp(header, pos->header)) &&
+ (0 == strcmp(content, pos->value)) ) {
+ free(pos->header);
+ free(pos->value);
+ if (prev == NULL)
+ 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 added to a response.
+ *
+ * @param iterator callback to call on each header;
+ * maybe NULL (then just count headers)
+ * @param iterator_cls extra argument to iterator
+ * @return number of entries iterated over
+ */
+int
+MHD_get_response_headers(struct MHD_Response * response,
+ MHD_KeyValueIterator * iterator,
+ void * iterator_cls) {
+ struct MHD_HTTP_Header * pos;
+ int numHeaders = 0;
+ pos = response->first_header;
+ while (pos != NULL) {
+ numHeaders++;
+ if ( (iterator != NULL) &&
+ (MHD_YES != iterator(iterator_cls,
+ pos->kind,
+ pos->header,
+ pos->value)) )
+ break;
+ pos = pos->next;
+ }
+ return numHeaders;
+}
+
+
+/**
+ * Create a response object. The response object can be extended with
+ * header information and then be used any number of times.
+ *
+ * @param size size of the data portion of the response, -1 for unknown
+ * @param crc callback to use to obtain response data
+ * @param crc_cls extra argument to crc
+ * @param crfc callback to call to free crc_cls resources
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ */
+struct MHD_Response *
+MHD_create_response_from_callback(size_t size,
+ MHD_ContentReaderCallback crc,
+ void * crc_cls,
+ MHD_ContentReaderFreeCallback crfc) {
+ struct MHD_Response * retVal;
+
+ if (crc == NULL)
+ return NULL;
+ retVal = malloc(sizeof(struct MHD_Response));
+ memset(retVal,
+ 0,
+ sizeof(struct MHD_Response));
+ if (pthread_mutex_init(&retVal->mutex, NULL) != 0) {
+ free(retVal);
+ return NULL;
+ }
+ retVal->crc = crc;
+ retVal->crfc = crfc;
+ retVal->crc_cls = crc_cls;
+ retVal->reference_count = 1;
+ retVal->total_size = size;
+ return retVal;
+}
+
+/**
+ * Create a response object. The response object can be extended with
+ * header information and then be used any number of times.
+ *
+ * @param size size of the data portion of the response
+ * @param data the data itself
+ * @param must_free libmicrohttpd should free data when done
+ * @param must_copy libmicrohttpd must make a copy of data
+ * right away, the data maybe released anytime after
+ * this call returns
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ */
+struct MHD_Response *
+MHD_create_response_from_data(size_t size,
+ void * data,
+ int must_free,
+ int must_copy) {
+ struct MHD_Response * retVal;
+ void * tmp;
+
+ if ( (data == NULL) &&
+ (size > 0) )
+ return NULL;
+ retVal = malloc(sizeof(struct MHD_Response));
+ memset(retVal,
+ 0,
+ sizeof(struct MHD_Response));
+ if (pthread_mutex_init(&retVal->mutex, NULL) != 0) {
+ free(retVal);
+ return NULL;
+ }
+ if ( (must_copy) &&
+ (size > 0) ) {
+ tmp = malloc(size);
+ memcpy(tmp,
+ data,
+ size);
+ must_free = 1;
+ data = tmp;
+ }
+ retVal->crc = NULL;
+ retVal->crfc = must_free ? &free : NULL;
+ retVal->crc_cls = must_free ? data : NULL;
+ retVal->reference_count = 1;
+ retVal->total_size = size;
+ retVal->data = data;
+ retVal->data_size = size;
+ return retVal;
+}
+
+/**
+ * Destroy a response object and associated resources. Note that
+ * libmicrohttpd may keep some of the resources around if the response
+ * is still in the queue for some clients, so the memory may not
+ * necessarily be freed immediatley.
+ */
+void
+MHD_destroy_response(struct MHD_Response * response) {
+ struct MHD_HTTP_Header * pos;
+
+ if (response == NULL)
+ return;
+ pthread_mutex_lock(&response->mutex);
+ if (0 != --response->reference_count) {
+ pthread_mutex_unlock(&response->mutex);
+ return;
+ }
+ pthread_mutex_unlock(&response->mutex);
+ pthread_mutex_destroy(&response->mutex);
+ while (response->first_header != NULL) {
+ pos = response->first_header;
+ response->first_header = pos->next;
+ free(pos->header);
+ free(pos->value);
+ free(pos);
+ }
+ free(response);
+}
+
+
+void
+MHD_increment_response_rc(struct MHD_Response * response) {
+ pthread_mutex_lock(&response->mutex);
+ response->reference_count++;
+ pthread_mutex_unlock(&response->mutex);
+}
+
+
+/* end of response.c */