| 192 | resp.keep_alive(true); |
| 193 | } |
| 194 | int handle_request(Request &req, Response &resp, std::string_view prefix) override { |
| 195 | LOG_DEBUG("enter fs handler"); |
| 196 | DEFER(LOG_DEBUG("leave fs handler")); |
| 197 | auto target = req.target(); |
| 198 | auto pos = target.find("?"); |
| 199 | estring_view query; |
| 200 | if (pos != std::string_view::npos) { |
| 201 | query = target.substr(pos + 1); |
| 202 | target = target.substr(0, pos); |
| 203 | } |
| 204 | |
| 205 | estring_view filename(target); |
| 206 | if (!prefix.empty()) |
| 207 | filename = filename.substr(prefix.size() - 1); |
| 208 | |
| 209 | LOG_DEBUG(VALUE(filename)); |
| 210 | auto file = m_fs->open(filename.extract_c_str(), O_RDONLY); |
| 211 | if (!file) { |
| 212 | failed_resp(resp); |
| 213 | LOG_ERROR_RETURN(0, 0, "open file ` failed", target); |
| 214 | } |
| 215 | DEFER(delete file); |
| 216 | if (!query.empty()) |
| 217 | file->ioctl(fs::HTTP_URL_PARAM, (const char*) query.extract_c_str()); |
| 218 | |
| 219 | struct stat buf; |
| 220 | if (file->fstat(&buf) < 0) { |
| 221 | failed_resp(resp); |
| 222 | LOG_ERROR_RETURN(0, 0, "stat file ` failed", target); |
| 223 | } |
| 224 | auto file_end_pos = buf.st_size - 1; |
| 225 | auto range = req.headers.range(); |
| 226 | if (range.first < 0) { |
| 227 | range.first = file_end_pos - range.second; |
| 228 | range.second = file_end_pos; |
| 229 | } |
| 230 | if (range.second < 0 || range.second > file_end_pos) { |
| 231 | range.second = file_end_pos; |
| 232 | } |
| 233 | if (buf.st_size > 0 && |
| 234 | (range.second < range.first || range.first > file_end_pos)) { |
| 235 | failed_resp(resp, 416); |
| 236 | LOG_ERROR_RETURN(0, 0, "invalid request range ", target); |
| 237 | } |
| 238 | auto req_size = range.second - range.first + 1; |
| 239 | if (req_size == buf.st_size) |
| 240 | resp.set_result(200); |
| 241 | else { |
| 242 | resp.set_result(206); |
| 243 | resp.headers.content_range(range.first, range.second, buf.st_size); |
| 244 | } |
| 245 | |
| 246 | resp.headers.content_length(req_size); |
| 247 | if (req.verb() == Verb::HEAD) |
| 248 | return 0; |
| 249 | file->lseek(range.first, SEEK_SET); |
| 250 | return resp.write_stream(&*file, req_size); |
| 251 | } |
no test coverage detected