/** * Entry point to demo. Note: this HTTP server will make all * files in the current directory and its subdirectories available * to anyone. Press ENTER to stop the server once it has started. * * @param argc number of arguments in argv * @param argv first and only argument should be the port number * @return 0 on success */ int main (int argc, char *const *argv) { struct MHD_Daemon *d; unsigned int port; if ( (argc != 2) || (1 != sscanf (argv[1], "%u", &port)) || (UINT16_MAX < port) ) { fprintf (stderr, "%s PORT\n", argv[0]); return 1; } #ifndef MINGW ignore_sigpipe (); #endif magic = magic_open (MAGIC_MIME_TYPE); (void) magic_load (magic, NULL); (void) pthread_mutex_init (&mutex, NULL); file_not_found_response = MHD_create_response_from_buffer (strlen (FILE_NOT_FOUND_PAGE), (void *) FILE_NOT_FOUND_PAGE, MHD_RESPMEM_PERSISTENT); mark_as_html (file_not_found_response); request_refused_response = MHD_create_response_from_buffer (strlen (REQUEST_REFUSED_PAGE), (void *) REQUEST_REFUSED_PAGE, MHD_RESPMEM_PERSISTENT); mark_as_html (request_refused_response); internal_error_response = MHD_create_response_from_buffer (strlen (INTERNAL_ERROR_PAGE), (void *) INTERNAL_ERROR_PAGE, MHD_RESPMEM_PERSISTENT); mark_as_html (internal_error_response); update_directory (); d = MHD_start_daemon (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, port, NULL, NULL, &generate_page, NULL, MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (256 * 1024), #if PRODUCTION MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) (64), #endif MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) (120 /* seconds */), MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) NUMBER_OF_THREADS, MHD_OPTION_NOTIFY_COMPLETED, &response_completed_callback, NULL, MHD_OPTION_END); if (NULL == d) return 1; fprintf (stderr, "HTTP server running. Press ENTER to stop the server\n"); (void) getc (stdin); MHD_stop_daemon (d); MHD_destroy_response (file_not_found_response); MHD_destroy_response (request_refused_response); MHD_destroy_response (internal_error_response); update_cached_response (NULL); (void) pthread_mutex_destroy (&mutex); magic_close (magic); return 0; }
/** * Re-scan our local directory and re-build the index. */ static void update_directory () { static size_t initial_allocation = 32 * 1024; /* initial size for response buffer */ struct MHD_Response *response; struct ResponseDataContext rdc; unsigned int language_idx; unsigned int category_idx; const struct Language *language; const char *category; char dir_name[128]; struct stat sbuf; rdc.buf_len = initial_allocation; if (NULL == (rdc.buf = malloc (rdc.buf_len))) { update_cached_response (NULL); return; } rdc.off = snprintf (rdc.buf, rdc.buf_len, "%s", INDEX_PAGE_HEADER); for (language_idx = 0; NULL != languages[language_idx].dirname; language_idx++) { language = &languages[language_idx]; if (0 != stat (language->dirname, &sbuf)) continue; /* empty */ /* we ensured always +1k room, filenames are ~256 bytes, so there is always still enough space for the header without need for an additional reallocation check. */ rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off, "<h2>%s</h2>\n", language->longname); for (category_idx = 0; NULL != categories[category_idx]; category_idx++) { category = categories[category_idx]; snprintf (dir_name, sizeof (dir_name), "%s/%s", language->dirname, category); if (0 != stat (dir_name, &sbuf)) continue; /* empty */ /* we ensured always +1k room, filenames are ~256 bytes, so there is always still enough space for the header without need for an additional reallocation check. */ rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off, "<h3>%s</h3>\n", category); if (MHD_NO == list_directory (&rdc, dir_name)) { free (rdc.buf); update_cached_response (NULL); return; } } } /* we ensured always +1k room, filenames are ~256 bytes, so there is always still enough space for the footer without need for a final reallocation check. */ rdc.off += snprintf (&rdc.buf[rdc.off], rdc.buf_len - rdc.off, "%s", INDEX_PAGE_FOOTER); initial_allocation = rdc.buf_len; /* remember for next time */ response = MHD_create_response_from_buffer (rdc.off, rdc.buf, MHD_RESPMEM_MUST_FREE); mark_as_html (response); #if FORCE_CLOSE (void) MHD_add_response_header (response, MHD_HTTP_HEADER_CONNECTION, "close"); #endif update_cached_response (response); }