static liHandlerResult dirlist(liVRequest *vr, gpointer param, gpointer *context) { GString *listing; liStatCacheEntry *sce; dirlist_data *dd; UNUSED(context); switch (vr->request.http_method) { case LI_HTTP_METHOD_GET: case LI_HTTP_METHOD_HEAD: break; default: return LI_HANDLER_GO_ON; } if (li_vrequest_is_handled(vr)) return LI_HANDLER_GO_ON; if (vr->physical.path->len == 0) return LI_HANDLER_GO_ON; switch (li_stat_cache_get_dirlist(vr, vr->physical.path, &sce)) { case LI_HANDLER_GO_ON: break; case LI_HANDLER_WAIT_FOR_EVENT: return LI_HANDLER_WAIT_FOR_EVENT; default: return LI_HANDLER_ERROR; } dd = param; if (sce->data.failed) { /* stat failed */ int e = sce->data.err; li_stat_cache_entry_release(vr, sce); switch (e) { case ENOENT: case ENOTDIR: return LI_HANDLER_GO_ON; case EACCES: if (!li_vrequest_handle_direct(vr)) return LI_HANDLER_ERROR; vr->response.http_status = 403; return LI_HANDLER_GO_ON; default: VR_ERROR(vr, "stat('%s') failed: %s", sce->data.path->str, g_strerror(sce->data.err)); return LI_HANDLER_ERROR; } } else if (!S_ISDIR(sce->data.st.st_mode)) { li_stat_cache_entry_release(vr, sce); return LI_HANDLER_GO_ON; } else if (vr->request.uri.path->len == 0 || vr->request.uri.path->str[vr->request.uri.path->len-1] != '/') { li_stat_cache_entry_release(vr, sce); li_vrequest_redirect_directory(vr); return LI_HANDLER_GO_ON; } else { /* everything ok, we have the directory listing */ gboolean cachable; guint i, j; liStatCacheEntryData *sced; GString *mime_str, *encoded; GArray *directories, *files; gchar sizebuf[sizeof("999.9K")+1]; gchar datebuf[sizeof("2005-Jan-01 22:23:24")+1]; guint datebuflen; struct tm tm; gboolean hide; if (!li_vrequest_handle_direct(vr)) { li_stat_cache_entry_release(vr, sce); return LI_HANDLER_ERROR; } vr->response.http_status = 200; if (dd->debug) VR_DEBUG(vr, "dirlist for \"%s\", %u entries", sce->data.path->str, sce->dirlist->len); li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), GSTR_LEN(dd->content_type)); li_etag_set_header(vr, &sce->data.st, &cachable); if (cachable) { vr->response.http_status = 304; li_stat_cache_entry_release(vr, sce); return LI_HANDLER_GO_ON; } /* temporary string for encoded names */ encoded = g_string_sized_new(64-1); /* seperate directories from other files */ directories = g_array_sized_new(FALSE, FALSE, sizeof(guint), 16); files = g_array_sized_new(FALSE, FALSE, sizeof(guint), sce->dirlist->len); for (i = 0; i < sce->dirlist->len; i++) { sced = &g_array_index(sce->dirlist, liStatCacheEntryData, i); hide = FALSE; /* ingore entries where the stat() failed */ if (sced->failed) continue; if (dd->hide_dotfiles && sced->path->str[0] == '.') continue; if (dd->hide_tildefiles && sced->path->str[sced->path->len-1] == '~') continue; for (j = 0; j < dd->exclude_suffix->len; j++) { if (li_string_suffix(sced->path, GSTR_LEN((GString*)g_ptr_array_index(dd->exclude_suffix, j)))) { hide = TRUE; break; } } if (hide) continue; for (j = 0; j < dd->exclude_prefix->len; j++) { if (li_string_prefix(sced->path, GSTR_LEN((GString*)g_ptr_array_index(dd->exclude_prefix, j)))) { hide = TRUE; break; } } if (hide) continue; if (S_ISDIR(sced->st.st_mode)) { if (dd->hide_directories) continue; g_array_append_val(directories, i); } else { if ((dd->include_header || dd->hide_header) && g_str_equal(sced->path, "HEADER.txt")) { if (dd->hide_header) continue; } else if ((dd->include_readme || dd->hide_readme) && g_str_equal(sced->path, "README.txt")) { if (dd->hide_readme) continue; } g_array_append_val(files, i); } } listing = g_string_sized_new(4*1024-1); g_string_append_printf(listing, html_header_start, vr->request.uri.path->str); if (dd->css) { /* custom css */ g_string_append_len(listing, CONST_STR_LEN(" <link rel=\"stylesheet\" type=\"text/css\" href=\"")); g_string_append_len(listing, GSTR_LEN(dd->css)); g_string_append_len(listing, CONST_STR_LEN("\" />\n")); } else { /* default css */ g_string_append_len(listing, CONST_STR_LEN(html_css)); } g_string_append_len(listing, CONST_STR_LEN(html_header_end)); try_append_file(vr, &listing, "HEADER.txt", dd->encode_header); g_string_append_printf(listing, html_table_start, vr->request.uri.path->str); if (0 != strcmp("/", vr->request.uri.path->str)) { g_string_append_printf(listing, html_table_row, '0', "../", "Parent Directory", (gint64)0, "", (gint64)0, "-", "Directory"); } /* list directories */ if (!dd->hide_directories) { for (i = 0; i < directories->len; i++) { sced = &g_array_index(sce->dirlist, liStatCacheEntryData, g_array_index(directories, guint, i)); localtime_r(&(sced->st.st_mtime), &tm); datebuflen = strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm); datebuf[datebuflen] = '\0'; g_string_append_len(listing, CONST_STR_LEN(" <tr group=\"1\"><td><a href=\"")); li_string_encode(sced->path->str, encoded, LI_ENCODING_URI); g_string_append_len(listing, GSTR_LEN(encoded)); g_string_append_len(listing, CONST_STR_LEN("/\">")); li_string_encode(sced->path->str, encoded, LI_ENCODING_HTML); g_string_append_len(listing, GSTR_LEN(encoded)); g_string_append_len(listing, CONST_STR_LEN("</a></td><td class=\"modified\" val=\"")); li_string_append_int(listing, sced->st.st_mtime); g_string_append_len(listing, CONST_STR_LEN("\">")); g_string_append_len(listing, datebuf, datebuflen); g_string_append_len(listing, CONST_STR_LEN("</td>" "<td class=\"size\" val=\"0\">-</td>" "<td class=\"type\">Directory</td></tr>\n")); } } /*g_string_append_len(listing, CONST_STR_LEN("<tr><td colspan=\"4\"> </td></tr>\n"));*/ /* list files */ for (i = 0; i < files->len; i++) { sced = &g_array_index(sce->dirlist, liStatCacheEntryData, g_array_index(files, guint, i)); mime_str = li_mimetype_get(vr, sced->path); localtime_r(&(sced->st.st_mtime), &tm); datebuflen = strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm); datebuf[datebuflen] = '\0'; dirlist_format_size(sizebuf, sced->st.st_size); g_string_append_len(listing, CONST_STR_LEN(" <tr group=\"2\"><td><a href=\"")); li_string_encode(sced->path->str, encoded, LI_ENCODING_URI); g_string_append_len(listing, GSTR_LEN(encoded)); g_string_append_len(listing, CONST_STR_LEN("\">")); li_string_encode(sced->path->str, encoded, LI_ENCODING_HTML); g_string_append_len(listing, GSTR_LEN(encoded)); g_string_append_len(listing, CONST_STR_LEN( "</a></td>" "<td class=\"modified\" val=\"")); li_string_append_int(listing, sced->st.st_mtime); g_string_append_len(listing, CONST_STR_LEN("\">")); g_string_append_len(listing, datebuf, datebuflen); g_string_append_len(listing, CONST_STR_LEN("</td><td class=\"size\" val=\"")); li_string_append_int(listing, sced->st.st_size); g_string_append_len(listing, CONST_STR_LEN("\">")); g_string_append(listing, sizebuf); g_string_append_len(listing, CONST_STR_LEN("</td><td class=\"type\">")); if (mime_str) { g_string_append_len(listing, GSTR_LEN(mime_str)); } else { g_string_append_len(listing, CONST_STR_LEN("application/octet-stream")); } g_string_append_len(listing, CONST_STR_LEN("</td></tr>\n")); /* g_string_append_printf(listing, html_table_row, sced->path->str, sced->path->str, (gint64)sced->st.st_mtime, datebuf, sced->st.st_size, sizebuf, mime_str ? mime_str->str : "application/octet-stream"); */ } g_string_append_len(listing, CONST_STR_LEN(html_table_end)); try_append_file(vr, &listing, "README.txt", dd->encode_readme); if (dd->include_sort) { g_string_append_len(listing, CONST_STR_LEN(javascript_sort)); } g_string_append_printf(listing, html_footer, CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_TAG).string->str); li_chunkqueue_append_string(vr->direct_out, listing); g_string_free(encoded, TRUE); g_array_free(directories, TRUE); g_array_free(files, TRUE); } li_stat_cache_entry_release(vr, sce); return LI_HANDLER_GO_ON; }
static liHandlerResult flv(liVRequest *vr, gpointer param, gpointer *context) { gchar *start; guint len; goffset pos; liHandlerResult res; gboolean cachable; struct stat st; int err; int fd = -1; UNUSED(context); UNUSED(param); if (li_vrequest_is_handled(vr)) return LI_HANDLER_GO_ON; res = li_stat_cache_get(vr, vr->physical.path, &st, &err, &fd); if (res == LI_HANDLER_WAIT_FOR_EVENT) return res; if (res == LI_HANDLER_ERROR) { /* open or fstat failed */ if (fd != -1) close(fd); if (!li_vrequest_handle_direct(vr)) return LI_HANDLER_ERROR; switch (err) { case ENOENT: case ENOTDIR: vr->response.http_status = 404; return LI_HANDLER_GO_ON; case EACCES: vr->response.http_status = 403; return LI_HANDLER_GO_ON; default: VR_ERROR(vr, "stat() or open() for '%s' failed: %s", vr->physical.path->str, g_strerror(err)); return LI_HANDLER_ERROR; } } else if (S_ISDIR(st.st_mode)) { if (fd != -1) close(fd); return LI_HANDLER_GO_ON; } else if (!S_ISREG(st.st_mode)) { if (fd != -1) close(fd); if (!li_vrequest_handle_direct(vr)) return LI_HANDLER_ERROR; vr->response.http_status = 403; } else { liChunkFile *cf; #ifdef FD_CLOEXEC fcntl(fd, F_SETFD, FD_CLOEXEC); #endif if (!li_vrequest_handle_direct(vr)) { close(fd); return LI_HANDLER_ERROR; } if (li_querystring_find(vr->request.uri.query, CONST_STR_LEN("start"), &start, &len)) { guint i; pos = 0; for (i = 0; i < len; i++) { if (start[i] >= '0' && start[i] <= '9') { pos *= 10; pos += start[i] - '0'; } } } else { pos = 0; } li_etag_set_header(vr, &st, &cachable); if (cachable) { vr->response.http_status = 304; close(fd); return LI_HANDLER_GO_ON; } vr->response.http_status = 200; li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv")); if (pos < 0 || pos > st.st_size) pos = 0; if (pos != 0) li_chunkqueue_append_mem(vr->direct_out, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9")); cf = li_chunkfile_new(NULL, fd, FALSE); li_chunkqueue_append_chunkfile(vr->direct_out, cf, pos, st.st_size - pos); li_chunkfile_release(cf); } return LI_HANDLER_GO_ON; }