-STATIC int servFile (struct MHD_Connection *connection, AFB_session *session, const char *url, AFB_staticfile *staticfile) {
- const char *etagCache, *mimetype;
- char etagValue[15];
- struct MHD_Response *response;
- struct stat sbuf;
- int ret;
-
- if (fstat (staticfile->fd, &sbuf) != 0) {
- fprintf(stderr, "Fail to stat file: [%s] error:%s\n", staticfile->path, strerror(errno));
- goto abortRequest;
- }
-
- // if url is a directory let's add index.html and redirect client
- if (S_ISDIR (sbuf.st_mode)) {
- close (staticfile->fd); // close directory check for Index
-
- // No trailing '/'. Let's add one and redirect for relative paths to work
- if (url [strlen (url) -1] != '/') {
- response = MHD_create_response_from_buffer(0,"", MHD_RESPMEM_PERSISTENT);
- strncpy(staticfile->path, url, sizeof (staticfile->path));
- strncat(staticfile->path, "/", sizeof (staticfile->path));
- MHD_add_response_header (response, "Location", staticfile->path);
- MHD_queue_response (connection, MHD_HTTP_MOVED_PERMANENTLY, response);
- if (verbose) fprintf (stderr,"Adding trailing '/' [%s]\n",staticfile->path);
- goto sendRequest;
- }
-
- strncat (staticfile->path, OPA_INDEX, sizeof (staticfile->path));
- if (-1 == (staticfile->fd = open(staticfile->path, O_RDONLY)) || (fstat (staticfile->fd, &sbuf) != 0)) {
- fprintf(stderr, "No Index.html in direcory [%s]\n", staticfile->path);
- goto abortRequest;
- }
- } else if (! S_ISREG (sbuf.st_mode)) { // only standard file any other one including symbolic links are refused.
- close (staticfile->fd); // nothing useful to do with this file
- fprintf (stderr, "Fail file: [%s] is not a regular file\n", staticfile->path);
- const char *errorstr = "<html><body>Application Framework Binder Invalid file type</body></html>";
- response = MHD_create_response_from_buffer (strlen (errorstr),
- (void *) errorstr, MHD_RESPMEM_PERSISTENT);
- MHD_queue_response (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, response);
- goto sendRequest;
- }
-
- // https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=fr
- // ftp://ftp.heanet.ie/disk1/www.gnu.org/software/libmicrohttpd/doxygen/dc/d0c/microhttpd_8h.html
-
- // Check etag value and load file only when modification date changes
- etagCache = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_NONE_MATCH);
- computeEtag(etagValue, sizeof (etagValue), &sbuf);
-
- if (etagCache != NULL && strcmp(etagValue, etagCache) == 0) {
- close(staticfile->fd); // file did not change since last upload
- if (verbose) fprintf(stderr, "Not Modify: [%s]\n", staticfile->path);
- response = MHD_create_response_from_buffer(0, "", MHD_RESPMEM_PERSISTENT);
- MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, session->cacheTimeout); // default one hour cache
- MHD_add_response_header(response, MHD_HTTP_HEADER_ETAG, etagValue);
- MHD_queue_response(connection, MHD_HTTP_NOT_MODIFIED, response);
-
- } else { // it's a new file, we need to upload it to client
- // if we have magic let's try to guest mime type
- if (session->magic) {
- mimetype= magic_descriptor(session->magic, staticfile->fd);
- if (mimetype != NULL) MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, mimetype);
- } else mimetype="application/unknown";
-
- if (verbose) fprintf(stderr, "Serving: [%s] mime=%s\n", staticfile->path, mimetype);
- response = MHD_create_response_from_fd(sbuf.st_size, staticfile->fd);
- MHD_add_response_header(response, MHD_HTTP_HEADER_CACHE_CONTROL, session->cacheTimeout); // default one hour cache
- MHD_add_response_header(response, MHD_HTTP_HEADER_ETAG, etagValue);
- MHD_queue_response(connection, MHD_HTTP_OK, response);
- }
-
-sendRequest:
- MHD_destroy_response(response);
- return (MHD_YES);
-
-abortRequest:
- return (FAILED);