static void handle_content_type(response_t *resp, const char *filepath) { char *content_type = NULL, ext[20]; int dot_pos = -1; int i; size_t len = strlen(filepath); ENTRY item, *ret; for (i = len - 1; i > 0; i--) { if (filepath[i] == '.') { dot_pos = i; break; } } if (dot_pos < 0) { // No '.' found in the file name (no extension part) return; } strncpy(ext, filepath + 1 + dot_pos, 20); strlowercase(ext, ext, 20); debug("File extension: %s", ext); item.key = ext; if (hsearch_r(item, FIND, &ret, &std_mime_type_hash) == 0) { return; } content_type = (char*) ret->data; if (content_type != NULL) { debug("Content type: %s", content_type); response_set_header(resp, "Content-Type", content_type); } }
static int static_file_listdir(response_t *resp, const char *path, const char *realpath) { struct dirent **ent_list, *ent; int ent_len; char buf[2048]; int pos = 0, i; debug("Opening dir: %s", realpath); if ((ent_len = scandir(realpath, &ent_list, dir_filter, versionsort)) < 0) { return static_file_handle_error(resp, -1); } resp->status = STATUS_OK; resp->connection = CONN_CLOSE; response_set_header(resp, "Content-Type", "text/html; charset=UTF-8"); response_send_headers(resp, NULL); pos += snprintf(buf, 2048, listdir_header, path, path); for (i = 0; i < ent_len; i++) { ent = ent_list[i]; pos += snprintf(buf + pos, 2048 - pos, ent->d_type == DT_DIR ? listdir_dir : listdir_file, ent->d_name, ent->d_name); if (2048 - pos < 255) { response_write(resp, buf, pos, NULL); pos = 0; } free(ent); } free(ent_list); pos += snprintf(buf + pos, 2048 - pos, listdir_footer, _BREEZE_NAME); response_write(resp, buf, pos, NULL); return HANDLER_DONE; }
static SLVAL response_redirect(sl_vm_t* vm, SLVAL self, SLVAL url) { response(vm)->status = 302; response_set_header(vm, self, sl_make_cstring(vm, "Location"), url); sl_exit(vm, sl_make_int(vm, 0)); return self; /* never reached */ }
static int handle_cache(request_t *req, response_t *resp, const struct stat *st, const mod_static_conf_t *conf) { const char *if_mod_since, *if_none_match; char *etag; time_t mtime, req_mtime; int not_modified = 0; char *buf; char *cache_control; mtime = st->st_mtime; if_mod_since = request_get_header(req, "if-modified-since"); if (if_mod_since != NULL && parse_http_date(if_mod_since, &req_mtime) == 0 && req_mtime == mtime) { debug("Resource not modified"); not_modified = 1; } buf = response_alloc(resp, 32); format_http_date(&mtime, buf, 32); response_set_header(resp, "Last-Modified", buf); if (conf->enable_etag) { etag = generate_etag(st); if (not_modified) { if_none_match = request_get_header(req, "if-none-match"); if (if_none_match == NULL || strcmp(etag, if_none_match) != 0) { not_modified = 0; } } response_set_header(resp, "ETag", etag); } if (conf->expire_hours >= 0) { buf = response_alloc(resp, 32); mtime += conf->expire_hours * 3600; format_http_date(&mtime, buf, 32); response_set_header(resp, "Expires", buf); cache_control = response_alloc(resp, 20); snprintf(cache_control, 20, "max-age=%d", conf->expire_hours * 3600); } else { cache_control = "no-cache"; } response_set_header(resp, "Cache-Control", cache_control); return not_modified; }
static SLVAL response_set_cookie(sl_vm_t* vm, SLVAL self, SLVAL name, SLVAL value) { SLVAL header; sl_expect(vm, name, vm->lib.String); sl_expect(vm, value, vm->lib.String); name = sl_string_url_encode(vm, name); value = sl_string_url_encode(vm, value); header = name; header = sl_string_concat(vm, header, sl_make_cstring(vm, "=")); header = sl_string_concat(vm, header, value); return response_set_header(vm, self, sl_make_cstring(vm, "Set-Cookie"), header); }
int static_file_handle(request_t *req, response_t *resp, handler_ctx_t *ctx) { mod_static_conf_t *conf; char path[2048]; int fd = -1, res, use_301; struct stat st; size_t len, pathlen, filesize, fileoffset; ctx_state_t val; conf = (mod_static_conf_t*) ctx->conf; len = strlen(conf->root); strncpy(path, conf->root, 2048); if (path[len - 1] == '/') { path[len - 1] = '\0'; } if (req->path[0] != '/') { return response_send_status(resp, STATUS_BAD_REQUEST); } strncat(path, req->path, 2048 - len); debug("Request path: %s, real file path: %s", req->path, path); res = try_open_file(path, &fd, &st); if (res < 0) { return static_file_handle_error(resp, fd); } else if (res > 0) { // Is a directory, try index files. pathlen = strlen(path); use_301 = 0; if (path[pathlen - 1] != '/') { path[pathlen] = '/'; path[pathlen + 1] = '\0'; pathlen++; use_301 = 1; } //for (i = 0; i < 10 && res != 0 && conf->index[i] != NULL; i++) { // path[pathlen] = '\0'; // strncat(path, conf->index[i], 2048 - pathlen); // res = try_open_file(path, &fd, &st); //} path[pathlen] = '\0'; strncat(path, conf->index, 2048 - pathlen); res = try_open_file(path, &fd, &st); path[pathlen] = '\0'; if (res != 0) { if (conf->enable_list_dir) { if (use_301) { // TODO Support HTTPS snprintf(path, 2048, "http://%s%s/", req->host, req->path); response_set_header(resp, "Location", path); resp->status = STATUS_MOVED; resp->content_length = 0; response_send_headers(resp, NULL); return HANDLER_DONE; } show_hidden_file = conf->show_hidden_file; return static_file_listdir(resp, req->path, path); } else { return static_file_handle_error(resp, fd); } } } fileoffset = 0; filesize = st.st_size; res = handle_range(req, resp, &fileoffset, &filesize); if (res < 0) { resp->status = STATUS_OK; } else if (res == 0) { resp->status = STATUS_PARTIAL_CONTENT; } else { return response_send_status(resp, STATUS_RANGE_NOT_SATISFIABLE); } resp->content_length = filesize; handle_content_type(resp, path); if (handle_cache(req, resp, &st, conf)) { return response_send_status(resp, STATUS_NOT_MODIFIED); } val.as_int = fd; context_push(ctx, val); val.as_long = fileoffset; context_push(ctx, val); val.as_long = filesize; context_push(ctx, val); debug("sending headers"); response_send_headers(resp, static_file_write_content); return HANDLER_UNFISHED; }