static async Task <GeminiResponse> ReadMessage(SslStream sslStream) { // Read the message sent by the server. // The end of the message is signaled using the // "<EOF>" marker. byte[] buffer = new byte[2048]; int bytes = -1; bytes = await sslStream.ReadAsync(buffer, 0, buffer.Length); GeminiResponse resp = new GeminiResponse(buffer.ToList(), bytes); while (bytes != 0) { bytes = await sslStream.ReadAsync(buffer, 0, buffer.Length); resp.pyld.AddRange(buffer.Take(bytes)); } return(resp); }
public async static Task <IResponse> Fetch(Uri hostURL) { int refetchCount = 0; Refetch: // Stop unbounded redirects if (refetchCount >= 5) { return(new GeminiResponse { codeMajor = '3', codeMinor = '9', meta = "", pyld = Encoding.UTF8.GetBytes("Too many redirects!").ToList(), mime = "text/plain", encoding = "UTF-8" }); } refetchCount += 1; // Set remote port int port = hostURL.Port; if (port == -1) { port = DefaultPort; } // Create a TCP/IP client socket. // machineName is the host running the server application. TcpClient client; try { client = new TcpClient(hostURL.Host, port); } catch (Exception e) { Log.Error(e, "Connection failure"); throw e; } // Create an SSL stream that will close the client's stream. SslStream sslStream = new SslStream( client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null ); // The server name must match the name on the server certificate. try { await sslStream.AuthenticateAsClientAsync(hostURL.Host); } catch (AuthenticationException e) { Log.Error(e, "Authentication failure"); client.Close(); throw e; } // Gemini request format: URI\r\n byte[] messsage = Encoding.UTF8.GetBytes(hostURL.ToString() + "\r\n"); await sslStream.WriteAsync(messsage, 0, messsage.Count()); await sslStream.FlushAsync(); // Read message from the server. GeminiResponse resp = await ReadMessage(sslStream); // Close the client connection. client.Close(); // Determine what to do w/ that switch (resp.codeMajor) { //case '1': // Text input // TODO //break; case '2': // OK break; case '3': // Redirect hostURL = new Uri(resp.meta); goto Refetch; case '4': // Temporary failure case '5': // Permanent failure case '6': // Client cert required Log.Error(resp.ToString()); resp.pyld = Encoding.UTF8.GetBytes(resp.ToString()).ToList(); break; default: throw new Exception( string.Format("Invalid response code {0}", resp.codeMajor) ); } return(resp); }