int noit_rest_simple_file_handler(noit_http_rest_closure_t *restc, int npats, char **pats) { int drlen = 0; const char *document_root = NULL; const char *index_file = NULL; noit_http_session_ctx *ctx = restc->http_ctx; char file[PATH_MAX], rfile[PATH_MAX]; struct stat st; int fd; void *contents = MAP_FAILED; const char *dot = NULL, *slash; const char *content_type = "application/octet-stream"; if(npats != 1 || !noit_hash_retr_str(restc->ac->config, "document_root", strlen("document_root"), &document_root)) { goto not_found; } if(!noit_hash_retr_str(restc->ac->config, "index_file", strlen("index_file"), &index_file)) { index_file = "index.html"; } drlen = strlen(document_root); snprintf(file, sizeof(file), "%s/%s", document_root, pats[0]); if(file[strlen(file) - 1] == '/') { snprintf(file + strlen(file), sizeof(file) - strlen(file), "%s", index_file); } /* resolve */ if(realpath(file, rfile) == NULL) goto not_found; /* restrict */ if(strncmp(rfile, document_root, drlen)) goto denied; if(rfile[drlen] != '/' && rfile[drlen + 1] != '/') goto denied; /* stat */ /* coverity[fs_check_call] */ if(stat(rfile, &st) != 0) { switch (errno) { case EACCES: goto denied; default: goto not_found; } } /* open */ if(st.st_size > 0) { /* coverity[toctou] */ fd = open(rfile, O_RDONLY); if(fd < 0) goto not_found; contents = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if(contents == MAP_FAILED) goto not_found; } /* set content type */ slash = strchr(rfile, '/'); while(slash) { const char *nslash = strchr(slash+1, '/'); if(!nslash) break; slash = nslash; } if(slash) dot = strchr(slash+1, '.'); while(dot) { const char *ndot = strchr(dot+1, '.'); if(!ndot) break; dot = ndot; } /* If there is no extention, just use the filename */ if(!dot) dot = slash+1; if(dot) { char ext[PATH_MAX]; strlcpy(ext, "mime_type_", sizeof(ext)); strlcpy(ext+strlen(ext), dot+1, sizeof(ext)-strlen(ext)); if(!noit_hash_retr_str(restc->ac->config, ext, strlen(ext), &content_type)) { if(!noit_hash_retr_str(&mime_type_defaults, dot+1, strlen(dot+1), &content_type)) { content_type = "application/octet-stream"; } } } noit_http_response_ok(ctx, content_type); if(st.st_size > 0) { noit_http_response_append(ctx, contents, st.st_size); munmap(contents, st.st_size); } noit_http_response_end(ctx); return 0; denied: noit_http_response_denied(ctx, "text/html"); noit_http_response_end(ctx); return 0; not_found: noit_http_response_not_found(ctx, "text/html"); noit_http_response_end(ctx); return 0; }
int noit_rest_simple_file_handler(noit_http_rest_closure_t *restc, int npats, char **pats) { int drlen = 0; const char *document_root = NULL; const char *index_file = NULL; noit_http_session_ctx *ctx = restc->http_ctx; char file[PATH_MAX], rfile[PATH_MAX]; struct stat st; int fd; void *contents = MAP_FAILED; if(npats != 1 || !noit_hash_retr_str(restc->ac->config, "document_root", strlen("document_root"), &document_root)) { goto not_found; } if(!noit_hash_retr_str(restc->ac->config, "index_file", strlen("index_file"), &index_file)) { index_file = "index.html"; } drlen = strlen(document_root); snprintf(file, sizeof(file), "%s/%s", document_root, pats[0]); if(file[strlen(file) - 1] == '/') { snprintf(file + strlen(file), sizeof(file) - strlen(file), "%s", index_file); } /* resolve */ if(realpath(file, rfile) == NULL) goto not_found; /* restrict */ if(strncmp(rfile, document_root, drlen)) goto denied; if(rfile[drlen] != '/' && rfile[drlen + 1] != '/') goto denied; /* stat */ if(stat(rfile, &st) != 0) { switch (errno) { case EACCES: goto denied; default: goto not_found; } } /* open */ if(st.st_size > 0) { fd = open(rfile, O_RDONLY); if(fd < 0) goto not_found; contents = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if(contents == MAP_FAILED) goto not_found; } noit_http_response_ok(ctx, "text/html"); if(st.st_size > 0) { noit_http_response_append(ctx, contents, st.st_size); munmap(contents, st.st_size); } noit_http_response_end(ctx); return 0; denied: noit_http_response_denied(ctx, "text/html"); noit_http_response_end(ctx); return 0; not_found: noit_http_response_not_found(ctx, "text/html"); noit_http_response_end(ctx); return 0; }