public HttpClientHolder(Stream transport, Socket client, HttpInitialRequest request) { this.Client = client; this.Transport = transport; this.Request = request; }
public static async ValueTask ProcessClient(HttpClientHolder holder, HttpInitialRequest request) { var handler = HttpHandleStore.Check(request.Path); if (handler == null) { request.Path = Path.Combine(Directory.GetCurrentDirectory(), HttpConstant.RootDirectory, request.Path); if (!File.Exists(request.Path)) { await holder.SafeWriteAsync(HttpErrorResponses.Instance.NotFoundResponse); return; } } else { handler.Invoked?.Invoke(holder); return; } var mime = MimeProcessor.Interpret(request.Path); if (mime == null) { await holder.SafeWriteAsync(HttpErrorResponses.Instance.NotImplementedResponse); return; } var fileInfo = new FileInfo(request.Path); holder.Client.SendBufferSize = HttpConstant.FileBufferSize; var asyncFs = fileInfo.Length > 1024 * 1024; Stream fs; if (Cfg.EnableHttpCache && !Cfg.HttpCacheExclude.Contains(request.Path)) { var(stat, array, length) = HttpServerFileCache.TryGet(request.Path); if (stat) { Trace.Assert(array != null, "Http cache null L58/Client.Processor!"); fs = new MemoryStream(array, 0, length.Value); asyncFs = false; } else { var(success, bytes, stream) = await HttpServerFileCache.TryCache(request.Path, asyncFs); if (success) { fs = new MemoryStream(bytes, 0, (int)fileInfo.Length); asyncFs = false; } else { fs = stream; } } } else { fs = new FileStream(request.Path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, useAsync: asyncFs); } await using (fs) { if (request.Ranges == null || request.Ranges.Count == 0) { using var header = new HttpResponseHeaders(fileInfo.Length, ResponseStatusCode.Ok200, new IResponseField[] { new FieldServer(HttpConstant.ServerName), new FieldContentType(mime), new FieldAcceptRanges(HttpConstant.AcceptRanges), }, request.HttpVersion); var headerData = header.Compile(); if (!await holder.SafeWriteAsync(headerData.Item1, headerData.Item2)) { return; } if (request.Method == HttpInitialRequestMethod.HEAD) { return; } await CopyStream(fileInfo, fs, holder, fileInfo.Length, asyncFs); return; } foreach (var range in request.Ranges) { switch (range.Method) { case HttpRangeRequestMethod.SliceFromToEnd: { // implemented, tested if (fs.Length < range.Range.From) { return; } using var header = new HttpResponseHeaders(fileInfo.Length, ResponseStatusCode.PartialContent206, new IResponseField[] { new FieldContentRange(true, range.Range.From, fileInfo.Length - 1, fileInfo.Length), new FieldServer(HttpConstant.ServerName), new FieldContentType(mime), new FieldAcceptRanges(HttpConstant.AcceptRanges), }, request.HttpVersion); var headerData = header.Compile(); if (!await holder.SafeWriteAsync(headerData.Item1, headerData.Item2)) { return; } if (request.Method == HttpInitialRequestMethod.HEAD) { return; } fs.Seek((long)range.Range.From !, SeekOrigin.Begin); await CopyStream(fileInfo, fs, holder, (int)(fs.Length - range.Range.From), asyncFs); return; } case HttpRangeRequestMethod.SendAll: { // implemented, tested using var header = new HttpResponseHeaders(fileInfo.Length, ResponseStatusCode.PartialContent206, new IResponseField[] { new FieldContentRange(true, 0, fileInfo.Length - 1, fileInfo.Length), new FieldServer(HttpConstant.ServerName), new FieldContentType(mime), new FieldAcceptRanges(HttpConstant.AcceptRanges), }, request.HttpVersion); var headerData = header.Compile(); if (!await holder.SafeWriteAsync(headerData.Item1, headerData.Item2)) { return; } if (request.Method == HttpInitialRequestMethod.HEAD) { return; } await CopyStream(fileInfo, fs, holder, (int)fs.Length, asyncFs); return; } case HttpRangeRequestMethod.SliceFromTo: { if (fs.Length < range.Range.From || fs.Length < range.Range.To) { // attacker. return; } using var header = new HttpResponseHeaders(fileInfo.Length, ResponseStatusCode.PartialContent206, new IResponseField[] { new FieldContentRange(true, range.Range.From, range.Range.To, fileInfo.Length), new FieldServer(HttpConstant.ServerName), new FieldContentType(mime), new FieldAcceptRanges(HttpConstant.AcceptRanges), }, request.HttpVersion); var headerData = header.Compile(); if (!await holder.SafeWriteAsync(headerData.Item1, headerData.Item2)) { return; } if (request.Method == HttpInitialRequestMethod.HEAD) { return; } fs.Seek((int)range.Range.From, SeekOrigin.Begin); await CopyStream(fileInfo, fs, holder, (long)(range.Range.To - range.Range.From) !, asyncFs); return; } case HttpRangeRequestMethod.SliceFromStartTo: { if (fs.Length < range.Range.To) { // attacker. return; } using var header = new HttpResponseHeaders(fileInfo.Length, ResponseStatusCode.PartialContent206, new IResponseField[] { new FieldContentRange(true, 0, range.Range.To, fileInfo.Length), new FieldServer(HttpConstant.ServerName), new FieldContentType(mime), new FieldAcceptRanges(HttpConstant.AcceptRanges), }, request.HttpVersion); var headerData = header.Compile(); if (!await holder.SafeWriteAsync(headerData.Item1, headerData.Item2) || range.Range.To == null) { return; } if (request.Method == HttpInitialRequestMethod.HEAD) { return; } await CopyStream(fileInfo, fs, holder, (long)range.Range.To, asyncFs); return; } default: return; // ?? } } } }