| 138 | } |
| 139 | |
| 140 | Result HttpAsyncFileServer::getFile(HttpAsyncFileServer::Stream& stream, HttpConnection& connection, |
| 141 | StringSpan filePath, bool sendBody, bool allowSpaFallback) |
| 142 | { |
| 143 | FileSystem fileSystem; |
| 144 | SC_TRY(fileSystem.init(directory.view())); |
| 145 | if (fileSystem.existsAndIsFile(filePath)) |
| 146 | { |
| 147 | FileSystem::FileStat fileStat; |
| 148 | SC_TRY(fileSystem.getFileStat(filePath, fileStat)); |
| 149 | StringSpan name, extension; |
| 150 | SC_TRY(HttpStringIterator::parseNameExtension(filePath, name, extension)); |
| 151 | StringPath path; |
| 152 | SC_TRY(path.assign(directory.view())); |
| 153 | SC_TRY(path.append("/")); |
| 154 | SC_TRY(path.append(filePath)); |
| 155 | |
| 156 | char lastModifiedData[128]; |
| 157 | size_t lastModifiedLength = 0; |
| 158 | SC_TRY(Internal::formatHttpDate(fileStat.modifiedTime.milliseconds, lastModifiedData, sizeof(lastModifiedData), |
| 159 | lastModifiedLength)); |
| 160 | StringSpan lastModified = {{lastModifiedData, lastModifiedLength}, false, StringEncoding::Ascii}; |
| 161 | |
| 162 | char etagData[64]; |
| 163 | size_t etagLength = 0; |
| 164 | StringSpan etag; |
| 165 | if (options.enableValidators) |
| 166 | { |
| 167 | SC_TRY(Internal::formatWeakETag(fileStat, etagData, sizeof(etagData), etagLength)); |
| 168 | etag = {{etagData, etagLength}, false, StringEncoding::Ascii}; |
| 169 | } |
| 170 | |
| 171 | if (options.enableValidators) |
| 172 | { |
| 173 | StringSpan ifNoneMatch; |
| 174 | if (connection.request.getHeader("If-None-Match", ifNoneMatch)) |
| 175 | { |
| 176 | if (Internal::etagMatchesIfNoneMatch(ifNoneMatch, etag)) |
| 177 | { |
| 178 | return Internal::sendNotModified(connection.response, lastModified, etag); |
| 179 | } |
| 180 | } |
| 181 | else |
| 182 | { |
| 183 | StringSpan ifModifiedSince; |
| 184 | if (connection.request.getHeader("If-Modified-Since", ifModifiedSince) and |
| 185 | ifModifiedSince == lastModified) |
| 186 | { |
| 187 | return Internal::sendNotModified(connection.response, lastModified, etag); |
| 188 | } |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | Internal::ByteRange byteRange; |
| 193 | byteRange.length = fileStat.fileSize; |
| 194 | if (options.enableRangeRequests) |
| 195 | { |
| 196 | StringSpan rangeHeader; |
| 197 | if (connection.request.getHeader("Range", rangeHeader)) |
nothing calls this directly
no test coverage detected