static void redirect_internally(h2o_redirect_handler_t *self, h2o_req_t *req, h2o_iovec_t dest) { h2o_iovec_t method; h2o_url_t input, resolved; /* resolve the URL */ if (h2o_url_parse_relative(dest.base, dest.len, &input) != 0) { h2o_req_log_error(req, MODULE_NAME, "invalid destination:%.*s", (int)dest.len, dest.base); goto SendInternalError; } if (input.scheme != NULL && input.authority.base != NULL) { resolved = input; } else { h2o_url_t base; /* we MUST to set authority to that of hostconf, or internal redirect might create a TCP connection */ if (h2o_url_init(&base, req->scheme, req->hostconf->authority.hostport, req->path) != 0) { h2o_req_log_error(req, MODULE_NAME, "failed to parse current authority:%.*s", (int)req->authority.len, req->authority.base); goto SendInternalError; } h2o_url_resolve(&req->pool, &base, &input, &resolved); } /* determine the method */ switch (self->status) { case 307: case 308: method = req->method; break; default: method = h2o_iovec_init(H2O_STRLIT("GET")); #ifndef _MSC_VER req->entity = (h2o_iovec_t){NULL}; #else req->entity = (h2o_iovec_t) { 0 }; #endif break; } h2o_reprocess_request_deferred(req, method, resolved.scheme, resolved.authority, resolved.path, NULL, 1); return; SendInternalError: h2o_send_error_503(req, "Internal Server Error", "internal server error", 0); }
static int specific_handler_on_req(h2o_handler_t *_self, h2o_req_t *req) { struct st_h2o_specific_file_handler_t *self = (void *)_self; struct st_h2o_sendfile_generator_t *generator; int is_dir; /* open file (or send error or return -1) */ if ((generator = create_generator(req, self->real_path.base, self->real_path.len, &is_dir, self->flags)) == NULL) { if (is_dir) { h2o_send_error_403(req, "Access Forbidden", "access forbidden", 0); } else if (errno == ENOENT) { return -1; } else if (errno == ENFILE || errno == EMFILE) { h2o_send_error_503(req, "Service Unavailable", "please try again later", 0); } else { h2o_send_error_403(req, "Access Forbidden", "access forbidden", 0); } return 0; } return serve_with_generator(generator, req, self->real_path.base, self->real_path.len, self->mime_type); }
static int on_req(h2o_handler_t *_self, h2o_req_t *req) { h2o_file_handler_t *self = (void *)_self; char *rpath; size_t rpath_len, req_path_prefix; struct st_h2o_sendfile_generator_t *generator = NULL; int is_dir; if (req->path_normalized.len < self->conf_path.len) { h2o_iovec_t dest = h2o_uri_escape(&req->pool, self->conf_path.base, self->conf_path.len, "/"); if (req->query_at != SIZE_MAX) dest = h2o_concat(&req->pool, dest, h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at)); h2o_send_redirect(req, 301, "Moved Permanently", dest.base, dest.len); return 0; } /* build path (still unterminated at the end of the block) */ req_path_prefix = self->conf_path.len; rpath = alloca(self->real_path.len + (req->path_normalized.len - req_path_prefix) + self->max_index_file_len + 1); rpath_len = 0; memcpy(rpath + rpath_len, self->real_path.base, self->real_path.len); rpath_len += self->real_path.len; memcpy(rpath + rpath_len, req->path_normalized.base + req_path_prefix, req->path_normalized.len - req_path_prefix); rpath_len += req->path_normalized.len - req_path_prefix; /* build generator (as well as terminating the rpath and its length upon success) */ if (rpath[rpath_len - 1] == '/') { h2o_iovec_t *index_file; for (index_file = self->index_files; index_file->base != NULL; ++index_file) { memcpy(rpath + rpath_len, index_file->base, index_file->len); rpath[rpath_len + index_file->len] = '\0'; if ((generator = create_generator(req, rpath, rpath_len + index_file->len, &is_dir, self->flags)) != NULL) { rpath_len += index_file->len; goto Opened; } if (is_dir) { /* note: apache redirects "path/" to "path/index.txt/" if index.txt is a dir */ h2o_iovec_t dest = h2o_concat(&req->pool, req->path_normalized, *index_file, h2o_iovec_init(H2O_STRLIT("/"))); dest = h2o_uri_escape(&req->pool, dest.base, dest.len, "/"); if (req->query_at != SIZE_MAX) dest = h2o_concat(&req->pool, dest, h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at)); h2o_send_redirect(req, 301, "Moved Permantently", dest.base, dest.len); return 0; } if (errno != ENOENT) break; } if (index_file->base == NULL && (self->flags & H2O_FILE_FLAG_DIR_LISTING) != 0) { rpath[rpath_len] = '\0'; int is_get = 0; if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("GET"))) { is_get = 1; } else if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("HEAD"))) { /* ok */ } else { send_method_not_allowed(req); return 0; } if (send_dir_listing(req, rpath, rpath_len, is_get) == 0) return 0; } } else { rpath[rpath_len] = '\0'; if ((generator = create_generator(req, rpath, rpath_len, &is_dir, self->flags)) != NULL) goto Opened; if (is_dir) { h2o_iovec_t dest = h2o_concat(&req->pool, req->path_normalized, h2o_iovec_init(H2O_STRLIT("/"))); dest = h2o_uri_escape(&req->pool, dest.base, dest.len, "/"); if (req->query_at != SIZE_MAX) dest = h2o_concat(&req->pool, dest, h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at)); h2o_send_redirect(req, 301, "Moved Permanently", dest.base, dest.len); return 0; } } /* failed to open */ if (errno == ENFILE || errno == EMFILE) { h2o_send_error_503(req, "Service Unavailable", "please try again later", 0); } else { if (h2o_mimemap_has_dynamic_type(self->mimemap) && try_dynamic_request(self, req, rpath, rpath_len) == 0) return 0; if (errno == ENOENT || errno == ENOTDIR) { return -1; } else { h2o_send_error_403(req, "Access Forbidden", "access forbidden", 0); } } return 0; Opened: return serve_with_generator(generator, req, rpath, rpath_len, h2o_mimemap_get_type_by_extension(self->mimemap, h2o_get_filext(rpath, rpath_len))); }