private async Task ServeAsync(Socket socket, NetworkStream ns, CancellationToken cancellationToken) { var buffer = new byte[1024]; var sr = new NetworkStreamReader(ns, buffer); // RequestLine: ex) GET / HTTP/1.1 var requestLine = await sr.ReadLineAsync(cancellationToken); var(isValid, method, path, version) = ParseRequestLine(requestLine); if (!isValid) { throw new InvalidReceiveDataException($"Invalid RequestLine: '{requestLine}'"); } // Console.WriteLine($"Method:'{method}' Path:'{path}' Version:'{version}'"); var headers = new Dictionary <string, string>(); while (true) { var line = await sr.ReadLineAsync(cancellationToken); if (line.Length == 0) { break; } string name, value; (isValid, name, value) = ParseHeader(line); if (!isValid) { throw new InvalidReceiveDataException($"Invalid Header: '{line}'"); } if (headers.ContainsKey(name)) { throw new InvalidReceiveDataException($"Duplicate Header: '{name}'"); } headers.Add(name, value); // Console.WriteLine($"Header:{name}, {value}"); } HTTPMethod _method; switch (method) { case "GET": _method = HTTPMethod.Get; break; case "POST": _method = HTTPMethod.Post; break; default: throw new NotImplementedException($"NotImplementedMethod : '{method}'"); } byte[] body = Array.Empty <byte>(); if (_method == HTTPMethod.Post && headers.TryGetValue(KnwonHeaders.ContentLength, out string contentLengthStr)) { int contentLength; if (!int.TryParse(contentLengthStr, out contentLength) || contentLength < 0) { throw new InvalidReceiveDataException($"Invalid Content-Length: {contentLengthStr}"); } if (contentLength > 2 * 1024 * 1024) { throw new InvalidReceiveDataException($"Too large Content-Length: {contentLengthStr}"); } // Console.WriteLine($"Content-Length:{contentLength}"); if (contentLength > 0) { var bodyBuffer = new byte[contentLength]; await sr.ReadBlockAsync(bodyBuffer, 0, contentLength, cancellationToken); body = bodyBuffer; } } var writeBuffer = new byte[1024]; var context = new Context( socket, new Request(path, headers, body), new ResponseWriter(sr, new NetworkStreamWriter(ns, writeBuffer)), cancellationToken ); var handleFunc = this.router.Find(_method, path); if (handleFunc == null) { await context.Response.WriteStatusCodeAsync(404, cancellationToken); await context.Response.WriteAsync("Not found.", cancellationToken); } else { await handleFunc(context); } await context.Response.FinishAsync(cancellationToken); }
public ResponseWriter(NetworkStreamReader sr, NetworkStreamWriter sw) { this.sr = sr; this.sw = sw; }