1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /** 21 * @file response.c 22 * @brief Methods for managing response objects 23 * @author Daniel Pittman 24 * @author Christian Grothoff 25 */ 26 27 #include "internal.h" 28 #include "response.h" 29 30 #if defined(_WIN32) && defined(MHD_W32_MUTEX_) 31 #ifndef WIN32_LEAN_AND_MEAN 32 #define WIN32_LEAN_AND_MEAN 1 33 #endif /* !WIN32_LEAN_AND_MEAN */ 34 #include <windows.h> 35 #endif /* _WIN32 && MHD_W32_MUTEX_ */ 36 #if defined(_WIN32) 37 #include <io.h> /* for lseek(), read() */ 38 #endif /* _WIN32 */ 39 40 41 /** 42 * Add a header or footer line to the response. 43 * 44 * @param response response to add a header to 45 * @param kind header or footer 46 * @param header the header to add 47 * @param content value to add 48 * @return #MHD_NO on error (i.e. invalid header or content format). 49 */ 50 static int 51 add_response_entry (struct MHD_Response *response, 52 enum MHD_ValueKind kind, 53 const char *header, 54 const char *content) 55 { 56 struct MHD_HTTP_Header *hdr; 57 58 if ( (NULL == response) || 59 (NULL == header) || 60 (NULL == content) || 61 (0 == strlen (header)) || 62 (0 == strlen (content)) || 63 (NULL != strchr (header, '\t')) || 64 (NULL != strchr (header, '\r')) || 65 (NULL != strchr (header, '\n')) || 66 (NULL != strchr (content, '\t')) || 67 (NULL != strchr (content, '\r')) || 68 (NULL != strchr (content, '\n')) ) 69 return MHD_NO; 70 if (NULL == (hdr = malloc (sizeof (struct MHD_HTTP_Header)))) 71 return MHD_NO; 72 if (NULL == (hdr->header = strdup (header))) 73 { 74 free (hdr); 75 return MHD_NO; 76 } 77 if (NULL == (hdr->value = strdup (content))) 78 { 79 free (hdr->header); 80 free (hdr); 81 return MHD_NO; 82 } 83 hdr->kind = kind; 84 hdr->next = response->first_header; 85 response->first_header = hdr; 86 return MHD_YES; 87 } 88 89 90 /** 91 * Add a header line to the response. 92 * 93 * @param response response to add a header to 94 * @param header the header to add 95 * @param content value to add 96 * @return #MHD_NO on error (i.e. invalid header or content format). 97 * @ingroup response 98 */ 99 int 100 MHD_add_response_header (struct MHD_Response *response, 101 const char *header, const char *content) 102 { 103 return add_response_entry (response, 104 MHD_HEADER_KIND, 105 header, 106 content); 107 } 108 109 110 /** 111 * Add a footer line to the response. 112 * 113 * @param response response to remove a header from 114 * @param footer the footer to delete 115 * @param content value to delete 116 * @return #MHD_NO on error (i.e. invalid footer or content format). 117 * @ingroup response 118 */ 119 int 120 MHD_add_response_footer (struct MHD_Response *response, 121 const char *footer, const char *content) 122 { 123 return add_response_entry (response, 124 MHD_FOOTER_KIND, 125 footer, 126 content); 127 } 128 129 130 /** 131 * Delete a header (or footer) line from the response. 132 * 133 * @param response response to remove a header from 134 * @param header the header to delete 135 * @param content value to delete 136 * @return #MHD_NO on error (no such header known) 137 * @ingroup response 138 */ 139 int 140 MHD_del_response_header (struct MHD_Response *response, 141 const char *header, 142 const char *content) 143 { 144 struct MHD_HTTP_Header *pos; 145 struct MHD_HTTP_Header *prev; 146 147 if ( (NULL == header) || (NULL == content) ) 148 return MHD_NO; 149 prev = NULL; 150 pos = response->first_header; 151 while (pos != NULL) 152 { 153 if ((0 == strcmp (header, pos->header)) && 154 (0 == strcmp (content, pos->value))) 155 { 156 free (pos->header); 157 free (pos->value); 158 if (NULL == prev) 159 response->first_header = pos->next; 160 else 161 prev->next = pos->next; 162 free (pos); 163 return MHD_YES; 164 } 165 prev = pos; 166 pos = pos->next; 167 } 168 return MHD_NO; 169 } 170 171 172 /** 173 * Get all of the headers (and footers) added to a response. 174 * 175 * @param response response to query 176 * @param iterator callback to call on each header; 177 * maybe NULL (then just count headers) 178 * @param iterator_cls extra argument to @a iterator 179 * @return number of entries iterated over 180 * @ingroup response 181 */ 182 int 183 MHD_get_response_headers (struct MHD_Response *response, 184 MHD_KeyValueIterator iterator, void *iterator_cls) 185 { 186 struct MHD_HTTP_Header *pos; 187 int numHeaders = 0; 188 189 for (pos = response->first_header; NULL != pos; pos = pos->next) 190 { 191 numHeaders++; 192 if ((NULL != iterator) && 193 (MHD_YES != iterator (iterator_cls, 194 pos->kind, pos->header, pos->value))) 195 break; 196 } 197 return numHeaders; 198 } 199 200 201 /** 202 * Get a particular header (or footer) from the response. 203 * 204 * @param response response to query 205 * @param key which header to get 206 * @return NULL if header does not exist 207 * @ingroup response 208 */ 209 const char * 210 MHD_get_response_header (struct MHD_Response *response, 211 const char *key) 212 { 213 struct MHD_HTTP_Header *pos; 214 215 if (NULL == key) 216 return NULL; 217 for (pos = response->first_header; NULL != pos; pos = pos->next) 218 if (0 == strcmp (key, pos->header)) 219 return pos->value; 220 return NULL; 221 } 222 223 224 /** 225 * Create a response object. The response object can be extended with 226 * header information and then be used any number of times. 227 * 228 * @param size size of the data portion of the response, #MHD_SIZE_UNKNOWN for unknown 229 * @param block_size preferred block size for querying crc (advisory only, 230 * MHD may still call @a crc using smaller chunks); this 231 * is essentially the buffer size used for IO, clients 232 * should pick a value that is appropriate for IO and 233 * memory performance requirements 234 * @param crc callback to use to obtain response data 235 * @param crc_cls extra argument to @a crc 236 * @param crfc callback to call to free @a crc_cls resources 237 * @return NULL on error (i.e. invalid arguments, out of memory) 238 * @ingroup response 239 */ 240 struct MHD_Response * 241 MHD_create_response_from_callback (uint64_t size, 242 size_t block_size, 243 MHD_ContentReaderCallback crc, 244 void *crc_cls, 245 MHD_ContentReaderFreeCallback crfc) 246 { 247 struct MHD_Response *response; 248 249 if ((NULL == crc) || (0 == block_size)) 250 return NULL; 251 if (NULL == (response = malloc (sizeof (struct MHD_Response) + block_size))) 252 return NULL; 253 memset (response, 0, sizeof (struct MHD_Response)); 254 response->fd = -1; 255 response->data = (void *) &response[1]; 256 response->data_buffer_size = block_size; 257 if (MHD_YES != MHD_mutex_create_ (&response->mutex)) 258 { 259 free (response); 260 return NULL; 261 } 262 response->crc = crc; 263 response->crfc = crfc; 264 response->crc_cls = crc_cls; 265 response->reference_count = 1; 266 response->total_size = size; 267 return response; 268 } 269 270 271 /** 272 * Set special flags and options for a response. 273 * 274 * @param response the response to modify 275 * @param flags to set for the response 276 * @param ... #MHD_RO_END terminated list of options 277 * @return #MHD_YES on success, #MHD_NO on error 278 */ 279 int 280 MHD_set_response_options (struct MHD_Response *response, 281 enum MHD_ResponseFlags flags, 282 ...) 283 { 284 va_list ap; 285 int ret; 286 enum MHD_ResponseOptions ro; 287 288 ret = MHD_YES; 289 response->flags = flags; 290 va_start (ap, flags); 291 while (MHD_RO_END != (ro = va_arg (ap, enum MHD_ResponseOptions))) 292 { 293 switch (ro) 294 { 295 default: 296 ret = MHD_NO; 297 break; 298 } 299 } 300 va_end (ap); 301 return ret; 302 } 303 304 305 /** 306 * Given a file descriptor, read data from the file 307 * to generate the response. 308 * 309 * @param cls pointer to the response 310 * @param pos offset in the file to access 311 * @param buf where to write the data 312 * @param max number of bytes to write at most 313 * @return number of bytes written 314 */ 315 static ssize_t 316 file_reader (void *cls, uint64_t pos, char *buf, size_t max) 317 { 318 struct MHD_Response *response = cls; 319 ssize_t n; 320 321 (void) lseek (response->fd, pos + response->fd_off, SEEK_SET); 322 n = read (response->fd, buf, max); 323 if (0 == n) 324 return MHD_CONTENT_READER_END_OF_STREAM; 325 if (n < 0) 326 return MHD_CONTENT_READER_END_WITH_ERROR; 327 return n; 328 } 329 330 331 /** 332 * Destroy file reader context. Closes the file 333 * descriptor. 334 * 335 * @param cls pointer to file descriptor 336 */ 337 static void 338 free_callback (void *cls) 339 { 340 struct MHD_Response *response = cls; 341 342 (void) close (response->fd); 343 response->fd = -1; 344 } 345 346 347 /** 348 * Create a response object. The response object can be extended with 349 * header information and then be used any number of times. 350 * 351 * @param size size of the data portion of the response 352 * @param fd file descriptor referring to a file on disk with the 353 * data; will be closed when response is destroyed; 354 * fd should be in 'blocking' mode 355 * @param offset offset to start reading from in the file; 356 * Be careful! `off_t` may have been compiled to be a 357 * 64-bit variable for MHD, in which case your application 358 * also has to be compiled using the same options! Read 359 * the MHD manual for more details. 360 * @return NULL on error (i.e. invalid arguments, out of memory) 361 * @ingroup response 362 */ 363 struct MHD_Response * 364 MHD_create_response_from_fd_at_offset (size_t size, 365 int fd, 366 off_t offset) 367 { 368 struct MHD_Response *response; 369 370 response = MHD_create_response_from_callback (size, 371 4 * 1024, 372 &file_reader, 373 NULL, 374 &free_callback); 375 if (NULL == response) 376 return NULL; 377 response->fd = fd; 378 response->fd_off = offset; 379 response->crc_cls = response; 380 return response; 381 } 382 383 384 /** 385 * Create a response object. The response object can be extended with 386 * header information and then be used any number of times. 387 * 388 * @param size size of the data portion of the response 389 * @param fd file descriptor referring to a file on disk with the data 390 * @return NULL on error (i.e. invalid arguments, out of memory) 391 * @ingroup response 392 */ 393 struct MHD_Response * 394 MHD_create_response_from_fd (size_t size, 395 int fd) 396 { 397 return MHD_create_response_from_fd_at_offset (size, fd, 0); 398 } 399 400 401 /** 402 * Create a response object. The response object can be extended with 403 * header information and then be used any number of times. 404 * 405 * @param size size of the @a data portion of the response 406 * @param data the data itself 407 * @param must_free libmicrohttpd should free data when done 408 * @param must_copy libmicrohttpd must make a copy of @a data 409 * right away, the data maybe released anytime after 410 * this call returns 411 * @return NULL on error (i.e. invalid arguments, out of memory) 412 * @deprecated use #MHD_create_response_from_buffer instead 413 * @ingroup response 414 */ 415 struct MHD_Response * 416 MHD_create_response_from_data (size_t size, 417 void *data, int must_free, int must_copy) 418 { 419 struct MHD_Response *response; 420 void *tmp; 421 422 if ((NULL == data) && (size > 0)) 423 return NULL; 424 if (NULL == (response = malloc (sizeof (struct MHD_Response)))) 425 return NULL; 426 memset (response, 0, sizeof (struct MHD_Response)); 427 response->fd = -1; 428 if (MHD_YES != MHD_mutex_create_ (&response->mutex)) 429 { 430 free (response); 431 return NULL; 432 } 433 if ((must_copy) && (size > 0)) 434 { 435 if (NULL == (tmp = malloc (size))) 436 { 437 (void) MHD_mutex_destroy_ (&response->mutex); 438 free (response); 439 return NULL; 440 } 441 memcpy (tmp, data, size); 442 must_free = MHD_YES; 443 data = tmp; 444 } 445 response->crc = NULL; 446 response->crfc = must_free ? &free : NULL; 447 response->crc_cls = must_free ? data : NULL; 448 response->reference_count = 1; 449 response->total_size = size; 450 response->data = data; 451 response->data_size = size; 452 return response; 453 } 454 455 456 /** 457 * Create a response object. The response object can be extended with 458 * header information and then be used any number of times. 459 * 460 * @param size size of the data portion of the response 461 * @param buffer size bytes containing the response's data portion 462 * @param mode flags for buffer management 463 * @return NULL on error (i.e. invalid arguments, out of memory) 464 * @ingroup response 465 */ 466 struct MHD_Response * 467 MHD_create_response_from_buffer (size_t size, 468 void *buffer, 469 enum MHD_ResponseMemoryMode mode) 470 { 471 return MHD_create_response_from_data (size, 472 buffer, 473 mode == MHD_RESPMEM_MUST_FREE, 474 mode == MHD_RESPMEM_MUST_COPY); 475 } 476 477 478 /** 479 * Destroy a response object and associated resources. Note that 480 * libmicrohttpd may keep some of the resources around if the response 481 * is still in the queue for some clients, so the memory may not 482 * necessarily be freed immediatley. 483 * 484 * @param response response to destroy 485 * @ingroup response 486 */ 487 void 488 MHD_destroy_response (struct MHD_Response *response) 489 { 490 struct MHD_HTTP_Header *pos; 491 492 if (NULL == response) 493 return; 494 (void) MHD_mutex_lock_ (&response->mutex); 495 if (0 != --(response->reference_count)) 496 { 497 (void) MHD_mutex_unlock_ (&response->mutex); 498 return; 499 } 500 (void) MHD_mutex_unlock_ (&response->mutex); 501 (void) MHD_mutex_destroy_ (&response->mutex); 502 if (response->crfc != NULL) 503 response->crfc (response->crc_cls); 504 while (NULL != response->first_header) 505 { 506 pos = response->first_header; 507 response->first_header = pos->next; 508 free (pos->header); 509 free (pos->value); 510 free (pos); 511 } 512 free (response); 513 } 514 515 516 void 517 MHD_increment_response_rc (struct MHD_Response *response) 518 { 519 (void) MHD_mutex_lock_ (&response->mutex); 520 (response->reference_count)++; 521 (void) MHD_mutex_unlock_ (&response->mutex); 522 } 523 524 525 /* end of response.c */ 526