private bool RequestReceived() { #if WINDOWS_UWP HttpRequest Request = new HttpRequest(this.header, this.dataStream, this.outputStream, this.client.Information.RemoteAddress.ToString() + ":" + this.client.Information.RemotePort); #else HttpRequest Request = new HttpRequest(this.header, this.dataStream, this.stream, this.client.Client.RemoteEndPoint.ToString()); #endif Request.clientConnection = this; bool?Queued = this.QueueRequest(Request); if (Queued.HasValue) { if (!Queued.Value && this.dataStream != null) { this.dataStream.Dispose(); } this.header = null; this.dataStream = null; this.transferEncoding = null; return(Queued.Value); } else { return(true); } }
/// <summary> /// Represets a response of an HTTP client request. /// </summary> /// <param name="TransferEncoding">Transfer encoding to use for transfering content to client.</param> /// <param name="HttpServer">HTTP Server serving the request.</param> /// <param name="Request">Request being served.</param> public HttpResponse(TransferEncoding TransferEncoding, HttpServer HttpServer, HttpRequest Request) : base() { this.responseStream = null; this.clientConnection = null; this.desiredTransferEncoding = TransferEncoding; this.httpServer = HttpServer; this.httpRequest = Request; if (Request != null && Request.Header.TryGetHeaderField("Connection", out HttpField Field) && Field.Value == "close") { this.closeAfterResponse = true; this.SetHeader("Connection", "close"); } }
private async Task <bool> BinaryDataReceived(byte[] Data, int Offset, int NrRead) { if (this.dataStream is null) { HttpFieldTransferEncoding TransferEncoding = this.header.TransferEncoding; if (!(TransferEncoding is null)) { if (TransferEncoding.Value == "chunked") { this.dataStream = new TemporaryStream(); this.transferEncoding = new ChunkedTransferEncoding(new BinaryOutputStream(this.dataStream), null); } else { await this.SendResponse(null, null, new HttpException(501, "Not Implemented", "Transfer encoding not implemented."), false); return(true); } } else { HttpFieldContentLength ContentLength = this.header.ContentLength; if (!(ContentLength is null)) { long l = ContentLength.ContentLength; if (l < 0) { await this.SendResponse(null, null, new HttpException(400, "Bad Request", "Negative content lengths invalid."), false); return(true); } if (l <= MaxInmemoryMessageSize) { this.dataStream = new MemoryStream((int)l); } else { this.dataStream = new TemporaryStream(); } this.transferEncoding = new ContentLengthEncoding(new BinaryOutputStream(this.dataStream), l, null); }
private void StartSendResponse(bool ExpectContent) { if (this.transferEncoding == null) { if (this.desiredTransferEncoding == null) { StringBuilder Output = new StringBuilder(); Output.Append("HTTP/1.1 "); Output.Append(this.statusCode.ToString()); Output.Append(' '); Output.Append(this.statusMessage); Output.Append("\r\nDate: "); Output.Append(CommonTypes.EncodeRfc822(this.date)); if (this.expires.HasValue) { Output.Append("\r\nExpires: "); Output.Append(CommonTypes.EncodeRfc822(this.expires.Value)); } Output.Append("\r\nServer: "); if (string.IsNullOrEmpty(this.server)) { Output.Append("Waher.Networking.HTTP"); } else { Output.Append(this.server + " (Waher.Networking.HTTP)"); } if (!string.IsNullOrEmpty(this.contentLanguage)) { Output.Append("\r\nContent-Language: "); Output.Append(this.contentLanguage); } if (!string.IsNullOrEmpty(this.contentType)) { Output.Append("\r\nContent-Type: "); Output.Append(this.contentType); if (this.contentType.StartsWith("text/") && !this.contentType.Contains("charset=")) { Output.Append("; charset="); Output.Append(this.encoding.WebName); } } if ((ExpectContent || this.contentLength.HasValue) && ((this.statusCode >= 100 && this.statusCode <= 199) || this.statusCode == 204 || this.statusCode == 304)) { throw new Exception("Content not allowed for status codes " + this.statusCode.ToString()); // When message bodies are required: // http://stackoverflow.com/questions/299628/is-an-entity-body-allowed-for-an-http-delete-request } if (this.contentLength.HasValue) { Output.Append("\r\nContent-Length: "); Output.Append(this.contentLength.Value.ToString()); this.transferEncoding = new ContentLengthEncoding(this.onlyHeader ? Stream.Null : this.responseStream, this.contentLength.Value, this.clientConnection); } else if (ExpectContent) { Output.Append("\r\nTransfer-Encoding: chunked"); this.transferEncoding = new ChunkedTransferEncoding(this.onlyHeader ? Stream.Null : this.responseStream, DefaultChunkSize, this.clientConnection); } else { if ((this.statusCode < 100 || this.statusCode > 199) && this.statusCode != 204 && this.statusCode != 304) { Output.Append("\r\nContent-Length: 0"); } this.transferEncoding = new ContentLengthEncoding(this.onlyHeader ? Stream.Null : this.responseStream, 0, this.clientConnection); } if (this.customHeaders != null) { foreach (KeyValuePair <string, string> P in this.customHeaders) { Output.Append("\r\n"); Output.Append(P.Key); Output.Append(": "); Output.Append(P.Value); } } if (this.cookies != null) { foreach (Cookie Cookie in this.cookies) { Output.Append("\r\nSet-Cookie: "); Output.Append(Cookie.ToString()); } } Output.Append("\r\n\r\n"); string Header = Output.ToString(); byte[] HeaderBin = InternetContent.ISO_8859_1.GetBytes(Header); if (this.responseStream == null || this.clientConnection.Disposed) { return; } this.responseStream.Write(HeaderBin, 0, HeaderBin.Length); this.clientConnection.Server.DataTransmitted(HeaderBin.Length); this.clientConnection.TransmitText(Header); } else { this.transferEncoding = this.desiredTransferEncoding; this.transferEncoding.BeforeContent(this, ExpectContent); } } }
private bool BinaryDataReceived(byte[] Data, int Offset, int NrRead) { if (this.dataStream == null) { HttpFieldTransferEncoding TransferEncoding = this.header.TransferEncoding; if (TransferEncoding != null) { if (TransferEncoding.Value == "chunked") { this.dataStream = new TemporaryFile(); this.transferEncoding = new ChunkedTransferEncoding(this.dataStream, null); } else { this.SendResponse(null, 501, "Not Implemented", false); return(true); } } else { HttpFieldContentLength ContentLength = this.header.ContentLength; if (ContentLength != null) { long l = ContentLength.ContentLength; if (l < 0) { this.SendResponse(null, 400, "Bad Request", false); return(true); } if (l <= MaxInmemoryMessageSize) { this.dataStream = new MemoryStream((int)l); } else { this.dataStream = new TemporaryFile(); } this.transferEncoding = new ContentLengthEncoding(this.dataStream, l, null); } else { this.SendResponse(null, 411, "Length Required", true); return(false); } } } bool Complete = this.transferEncoding.Decode(Data, Offset, NrRead, out int NrAccepted); if (this.HasSniffers) { if (Offset == 0 && NrAccepted == Data.Length) { this.ReceiveBinary(Data); } else { byte[] Data2 = new byte[NrAccepted]; Array.Copy(Data, Offset, Data2, 0, NrAccepted); this.ReceiveBinary(Data2); } } if (Complete) { if (this.transferEncoding.InvalidEncoding) { this.SendResponse(null, 400, "Bad Request", false); return(true); } else { Offset += NrAccepted; NrRead -= NrAccepted; if (!this.RequestReceived()) { return(false); } if (NrRead > 0) { return(this.BinaryHeaderReceived(Data, Offset, NrRead)); } else { return(true); } } } else if (this.dataStream.Position > MaxEntitySize) { this.dataStream.Dispose(); this.dataStream = null; this.SendResponse(null, 413, "Request Entity Too Large", true); return(false); } else { return(true); } }
private async Task <bool> BinaryDataReceived(byte[] Data, int Offset, int NrRead) { if (this.dataStream is null) { HttpFieldTransferEncoding TransferEncoding = this.header.TransferEncoding; if (TransferEncoding != null) { if (TransferEncoding.Value == "chunked") { this.dataStream = new TemporaryFile(); this.transferEncoding = new ChunkedTransferEncoding(new BinaryOutputStream(this.dataStream), null); } else { await this.SendResponse(null, null, new HttpException(501, "Not Implemented", "Transfer encoding not implemented."), false); return(true); } } else { HttpFieldContentLength ContentLength = this.header.ContentLength; if (ContentLength != null) { long l = ContentLength.ContentLength; if (l < 0) { await this.SendResponse(null, null, new HttpException(400, "Bad Request", "Negative content lengths invalid."), false); return(true); } if (l <= MaxInmemoryMessageSize) { this.dataStream = new MemoryStream((int)l); } else { this.dataStream = new TemporaryFile(); } this.transferEncoding = new ContentLengthEncoding(new BinaryOutputStream(this.dataStream), l, null); } else { await this.SendResponse(null, null, new HttpException(411, "Length Required", "Content Length required."), true); return(false); } } } ulong DecodingResponse = await this.transferEncoding.DecodeAsync(Data, Offset, NrRead); int NrAccepted = (int)DecodingResponse; bool Complete = (DecodingResponse & 0x100000000) != 0; if (this.HasSniffers) { if (Offset == 0 && NrAccepted == Data.Length) { this.ReceiveBinary(Data); } else { byte[] Data2 = new byte[NrAccepted]; Array.Copy(Data, Offset, Data2, 0, NrAccepted); this.ReceiveBinary(Data2); } } if (Complete) { if (this.transferEncoding.InvalidEncoding) { await this.SendResponse(null, null, new HttpException(400, "Bad Request", "Invalid transfer encoding."), false); return(true); } else if (this.transferEncoding.TransferError) { await this.SendResponse(null, null, new HttpException(500, "Internal Server Error", "Unable to transfer content to resource."), false); return(true); } else { Offset += NrAccepted; NrRead -= NrAccepted; if (!await this.RequestReceived()) { return(false); } if (NrRead > 0) { return(await this.BinaryHeaderReceived(Data, Offset, NrRead)); } else { return(true); } } } else if (this.dataStream.Position > MaxEntitySize) { this.dataStream.Dispose(); this.dataStream = null; await this.SendResponse(null, null, new HttpException(413, "Request Entity Too Large", "Maximum Entity Size: " + MaxEntitySize.ToString()), true); return(false); } else { return(true); } }