// We've found a CRLFCRLF sequence. Confirm the status code is 101 for upgrade. private HandshakeResponse InspectHanshake(byte[] buffer, int split, int limit) { var handshake = new HandshakeResponse { ResponseBytes = new ArraySegment <byte>(buffer, 0, split), ExtraData = new ArraySegment <byte>(buffer, split, limit), }; // Must be at least "HTTP/1.1 101\r\nConnection: Upgrade\r\nUpgrade: HTTP/2.0\r\n\r\n" Contract.Assert(split >= 0 && split - 1 < buffer.Length); var response = Encoding.ASCII.GetString(buffer, 0, split); if (_end == ConnectionEnd.Client) { int status = StatusCode.Code101SwitchingProtocols; string reasonPhrase = StatusCode.GetReasonPhrase(status); if (response.StartsWith(String.Format("{0} {1} {2}", Protocols.Http1, status.ToString(), reasonPhrase), StringComparison.OrdinalIgnoreCase) && response.IndexOf(String.Format("\r\n{0}: {1}\r\n", CommonHeaders.Connection, CommonHeaders.Upgrade), StringComparison.OrdinalIgnoreCase) >= 0 && response.IndexOf(String.Format("\r\n{0}: {1}\r\n", CommonHeaders.Upgrade, Protocols.Http2NoTls), StringComparison.OrdinalIgnoreCase) >= 0) { handshake.Result = HandshakeResult.Upgrade; } else { handshake.Result = HandshakeResult.NonUpgrade; } } else { if ( response.IndexOf(String.Format("\r\n{0}: {1}, {2}\r\n", CommonHeaders.Connection, CommonHeaders.Upgrade, CommonHeaders.Http2Settings), StringComparison.OrdinalIgnoreCase) >= 0 && response.IndexOf(String.Format("\r\n{0}: {1}\r\n", CommonHeaders.Upgrade, Protocols.Http2NoTls), StringComparison.OrdinalIgnoreCase) >= 0 && response.IndexOf(String.Format("\r\n{0}:", CommonHeaders.Http2Settings), StringComparison.OrdinalIgnoreCase) >= 0) { GetHeaders(response); handshake.Result = HandshakeResult.Upgrade; } else { handshake.Result = HandshakeResult.NonUpgrade; } } return(handshake); }
/// <summary> /// // TODO /// </summary> /// <param name="stream"></param> /// <param name="data"></param> /// <param name="statusCode"></param> /// <param name="headers"></param> /// <param name="closeConnection">we don’t currently support persistent connection via Http1.1 so closeConnection:true</param> /// <returns></returns> public static int SendResponse(Stream stream, byte[] data, int statusCode, IDictionary <string, string[]> headers = null, bool closeConnection = true) { string initialLine = "HTTP/1.1 " + statusCode + " " + StatusCode.GetReasonPhrase(statusCode) + "\r\n"; string headersPack = initialLine; if (headers == null) { headers = new Dictionary <string, string[]>(StringComparer.OrdinalIgnoreCase); } if (!headers.ContainsKey("Connection") && closeConnection) { headers.Add("Connection", new[] { "Close" }); } if (!headers.ContainsKey("Content-Length")) { headers.Add("Content-Length", new [] { Convert.ToString(data.Length) }); } headersPack = headers.Aggregate(headersPack, (current, header) => current + (header.Key + ": " + String.Join(",", header.Value) + "\r\n")) + "\r\n"; int sent = stream.Write(Encoding.UTF8.GetBytes(headersPack)); //Send headers and body separately //TODO It's needed for our client. Think out a way to avoid separate sending. stream.Flush(); if (data.Length > 0) { sent += stream.Write(data); } Thread.Sleep(200); stream.Flush(); return(sent); }
public static int SendResponse(SecureSocket socket, byte[] data, int statusCode, string contentType) { string initialLine = "HTTP/1.1 " + statusCode + " " + StatusCode.GetReasonPhrase(statusCode) + "\r\n"; var headers = new Dictionary <string, string>(); if (data.Length > 0) { headers.Add("Content-Type", contentType); } else { initialLine += "\r\n"; } int sent = socket.Send(Encoding.UTF8.GetBytes(initialLine)); SendHeaders(socket, headers, data.Length); if (data.Length > 0) { sent += socket.Send(data); } return(sent); }
public IDictionary <string, object> Handshake() { if (_end == ConnectionEnd.Client) { // Build the request var builder = new StringBuilder(); builder.AppendFormat("{0} {1} {2}\r\n", Verbs.Get, _headers[CommonHeaders.Path], Protocols.Http1); //TODO pass here requested filename builder.AppendFormat("Host: {0}\r\n", _headers[CommonHeaders.Host]); builder.Append(String.Format("{0}: {1}, {2}\r\n", CommonHeaders.Connection, CommonHeaders.Upgrade, CommonHeaders.Http2Settings)); builder.Append(String.Format("{0}: {1}\r\n", CommonHeaders.Upgrade, Protocols.Http2NoTls)); var settingsPayload = String.Format("{0}, {1}", 200000, 100); var settingsBytes = Encoding.UTF8.GetBytes(settingsPayload); var settingsBase64 = Convert.ToBase64String(settingsBytes); builder.Append(String.Format("{0}: {1}", CommonHeaders.Http2Settings, settingsBase64)); builder.Append("\r\n\r\n"); byte[] requestBytes = Encoding.UTF8.GetBytes(builder.ToString()); _handshakeResult = new Dictionary <string, object>(_headers) { { CommonHeaders.Method, Verbs.Get.ToLower() } }; IoStream.Write(requestBytes, 0, requestBytes.Length); IoStream.Flush(); ReadHeadersAndInspectHandshake(); } else { ReadHeadersAndInspectHandshake(); if (_response.Result == HandshakeResult.Upgrade) { const int status = StatusCode.Code101SwitchingProtocols; string protocol = Protocols.Http1; string postfix = StatusCode.GetReasonPhrase(status); var builder = new StringBuilder(); builder.AppendFormat("{0} {1} {2}\r\n", protocol, status, postfix); builder.Append(String.Format("{0}: {1}\r\n", CommonHeaders.Connection, CommonHeaders.Upgrade)); builder.Append(String.Format("{0}: {1}\r\n", CommonHeaders.Upgrade, Protocols.Http2NoTls)); builder.Append("\r\n"); byte[] requestBytes = Encoding.ASCII.GetBytes(builder.ToString()); IoStream.Write(requestBytes, 0, requestBytes.Length); IoStream.Flush(); } } if (!_wasResponseReceived) { throw new Http2HandshakeFailed(HandshakeFailureReason.Timeout); } if (_response.Result != HandshakeResult.Upgrade) { _handshakeResult.Add(HandshakeKeys.Successful, HandshakeKeys.False); var path = _headers[CommonHeaders.Path] as string; Http2Logger.LogDebug("Handling with http11"); var http11Adapter = new Http11ClientMessageHandler(IoStream, path); http11Adapter.HandleHttp11Response(_response.ResponseBytes.Array, 0, _response.ResponseBytes.Count); return(_handshakeResult); } _handshakeResult.Add(HandshakeKeys.Successful, HandshakeKeys.True); return(_handshakeResult); }