chunked_example.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. This file is part of libmicrohttpd
  3. Copyright (C) 2015 Christian Grothoff (and other contributing authors)
  4. Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
  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. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. /**
  18. * @file chunked_example.c
  19. * @brief example for generating chunked encoding with libmicrohttpd
  20. * @author Christian Grothoff
  21. * @author Karlson2k (Evgeny Grin)
  22. */
  23. #include "platform.h"
  24. #include <microhttpd.h>
  25. struct ResponseContentCallbackParam
  26. {
  27. const char *response_data;
  28. size_t response_size;
  29. };
  30. static ssize_t
  31. callback (void *cls,
  32. uint64_t pos,
  33. char *buf,
  34. size_t buf_size)
  35. {
  36. size_t size_to_copy;
  37. struct ResponseContentCallbackParam *const param =
  38. (struct ResponseContentCallbackParam *) cls;
  39. /* Note: 'pos' will never exceed size of transmitted data. */
  40. /* You can use 'pos == param->response_size' in next check. */
  41. if (pos >= param->response_size)
  42. { /* Whole response was sent. Signal end of response. */
  43. return MHD_CONTENT_READER_END_OF_STREAM;
  44. }
  45. /* Pseudo code. *
  46. if (data_not_ready)
  47. {
  48. // Callback will be called again on next loop.
  49. // Consider suspending connection until data will be ready.
  50. return 0;
  51. }
  52. * End of pseudo code. */
  53. if (buf_size < (param->response_size - pos))
  54. size_to_copy = buf_size;
  55. else
  56. size_to_copy = (size_t) (param->response_size - pos);
  57. memcpy (buf, param->response_data + pos, size_to_copy);
  58. /* Pseudo code. *
  59. if (error_preparing_response)
  60. {
  61. // Close connection with error.
  62. return MHD_CONTENT_READER_END_WITH_ERROR;
  63. }
  64. * End of pseudo code. */
  65. /* Return amount of data copied to buffer. */
  66. /* The 'buf_size' is always smaller than SSIZE_MAX therefore it's safe
  67. * to cast 'size_to_copy' to 'ssize_t'. */
  68. /* assert (size_to_copy <= buf_size); */
  69. return (ssize_t) size_to_copy;
  70. }
  71. static void
  72. free_callback_param (void *cls)
  73. {
  74. free (cls);
  75. }
  76. static const char simple_response_text[] =
  77. "<html><head><title>Simple response</title></head>"
  78. "<body>Simple response text</body></html>";
  79. static enum MHD_Result
  80. ahc_echo (void *cls,
  81. struct MHD_Connection *connection,
  82. const char *url,
  83. const char *method,
  84. const char *version,
  85. const char *upload_data,
  86. size_t *upload_data_size,
  87. void **req_cls)
  88. {
  89. static int aptr;
  90. struct ResponseContentCallbackParam *callback_param;
  91. struct MHD_Response *response;
  92. enum MHD_Result ret;
  93. (void) cls; /* Unused. Silent compiler warning. */
  94. (void) url; /* Unused. Silent compiler warning. */
  95. (void) version; /* Unused. Silent compiler warning. */
  96. (void) upload_data; /* Unused. Silent compiler warning. */
  97. (void) upload_data_size; /* Unused. Silent compiler warning. */
  98. if (0 != strcmp (method, "GET"))
  99. return MHD_NO; /* unexpected method */
  100. if (&aptr != *req_cls)
  101. {
  102. /* do never respond on first call */
  103. *req_cls = &aptr;
  104. return MHD_YES;
  105. }
  106. callback_param = malloc (sizeof(struct ResponseContentCallbackParam));
  107. if (NULL == callback_param)
  108. return MHD_NO; /* Not enough memory. */
  109. callback_param->response_data = simple_response_text;
  110. callback_param->response_size = (sizeof(simple_response_text)
  111. / sizeof(char)) - 1;
  112. *req_cls = NULL; /* reset when done */
  113. response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
  114. 1024,
  115. &callback,
  116. callback_param,
  117. &free_callback_param);
  118. if (NULL == response)
  119. {
  120. free (callback_param);
  121. return MHD_NO;
  122. }
  123. /* Enforce chunked response, even for non-keep-alive connection. */
  124. if (MHD_NO == MHD_add_response_header (response,
  125. MHD_HTTP_HEADER_TRANSFER_ENCODING,
  126. "chunked"))
  127. {
  128. free (callback_param);
  129. MHD_destroy_response (response);
  130. return MHD_NO;
  131. }
  132. ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
  133. MHD_destroy_response (response);
  134. return ret;
  135. }
  136. int
  137. main (int argc, char *const *argv)
  138. {
  139. struct MHD_Daemon *d;
  140. int port;
  141. if (argc != 2)
  142. {
  143. printf ("%s PORT\n", argv[0]);
  144. return 1;
  145. }
  146. port = atoi (argv[1]);
  147. if ( (1 > port) ||
  148. (port > UINT16_MAX) )
  149. {
  150. fprintf (stderr,
  151. "Port must be a number between 1 and 65535.\n");
  152. return 1;
  153. }
  154. d = MHD_start_daemon (/* MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, */
  155. MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
  156. /* MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_POLL, */
  157. /* MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_POLL, */
  158. /* MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, */
  159. (uint16_t) port,
  160. NULL, NULL,
  161. &ahc_echo, NULL,
  162. MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
  163. MHD_OPTION_END);
  164. if (NULL == d)
  165. return 1;
  166. (void) getc (stdin);
  167. MHD_stop_daemon (d);
  168. return 0;
  169. }