public static async Task <PythonProcess> AttachAsync(Uri uri, bool warnAboutAuthenticationErrors, TextWriter debugLog, CancellationToken ct) { string debugOptions = ""; if (uri.Query != null) { // It is possible to have more than one opt=... in the URI - the debug engine will always supply one based on // the options that it gets from VS, but the user can also explicitly specify it directly in the URI when doing // ptvsd attach (this is currently the only way to enable some flags when attaching, e.g. Django debugging). // ParseQueryString will automatically concat them all into a single value using commas. var queryParts = HttpUtility.ParseQueryString(uri.Query); debugOptions = queryParts[AD7Engine.DebugOptionsKey] ?? ""; } var debugConn = await ConnectAsync(uri, warnAboutAuthenticationErrors, debugLog, ct); try { var response = await debugConn.SendRequestAsync(new LDP.RemoteDebuggerAttachRequest() { debugOptions = debugOptions, }); if (!response.accepted) { throw new ConnectionException(ConnErrorMessages.RemoteAttachRejected); } var langVer = (PythonLanguageVersion)((response.pythonMajor << 8) | response.pythonMinor); if (!Enum.IsDefined(typeof(PythonLanguageVersion), langVer)) { langVer = PythonLanguageVersion.None; } PythonRemoteProcess process = new PythonRemoteProcess(response.processId, uri, langVer, debugLog); process.Connect(debugConn); debugConn = null; return(process); } catch (IOException ex) { throw new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex); } finally { if (debugConn != null) { debugConn.Dispose(); } } }
public static PythonProcess Attach(Uri uri, bool warnAboutAuthenticationErrors) { string debugOptions = ""; if (uri.Query != null) { // It is possible to have more than one opt=... in the URI - the debug engine will always supply one based on // the options that it gets from VS, but the user can also explicitly specify it directly in the URI when doing // ptvsd attach (this is currently the only way to enable some flags when attaching, e.g. Django debugging). // ParseQueryString will automatically concat them all into a single value using commas. var queryParts = HttpUtility.ParseQueryString(uri.Query); debugOptions = queryParts[AD7Engine.DebugOptionsKey] ?? ""; } var stream = Connect(uri, warnAboutAuthenticationErrors); try { stream.Write(AttachCommandBytes); stream.WriteString(debugOptions); string attachResp = stream.ReadAsciiString(Accepted.Length); if (attachResp != Accepted) { throw new ConnectionException(ConnErrorMessages.RemoteAttachRejected); } int pid = stream.ReadInt32(); int langMajor = stream.ReadInt32(); int langMinor = stream.ReadInt32(); int langMicro = stream.ReadInt32(); var langVer = (PythonLanguageVersion)((langMajor << 8) | langMinor); if (!Enum.IsDefined(typeof(PythonLanguageVersion), langVer)) { langVer = PythonLanguageVersion.None; } var process = new PythonRemoteProcess(pid, uri, langVer); process.Connect(stream); stream = null; return(process); } catch (IOException ex) { throw new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex); } finally { if (stream != null) { stream.Close(); } } }
public static PythonProcess Attach(Uri uri, bool warnAboutAuthenticationErrors) { var stream = Connect(uri, warnAboutAuthenticationErrors); try { stream.Write(AttachCommandBytes); string attachResp = stream.ReadAsciiString(Accepted.Length); if (attachResp != Accepted) { throw new ConnectionException(ConnErrorMessages.RemoteAttachRejected); } int pid = stream.ReadInt32(); int langMajor = stream.ReadInt32(); int langMinor = stream.ReadInt32(); int langMicro = stream.ReadInt32(); var langVer = (PythonLanguageVersion)((langMajor << 8) | langMinor); if (!Enum.IsDefined(typeof(PythonLanguageVersion), langVer)) { langVer = PythonLanguageVersion.None; } var process = new PythonRemoteProcess(pid, uri, langVer); process.Connect(stream); stream = null; return(process); } catch (IOException ex) { throw new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex); } finally { if (stream != null) { stream.Close(); } } }
public static PythonProcess Attach(Uri uri, bool warnAboutAuthenticationErrors) { string debugOptions = ""; if (uri.Query != null) { // It is possible to have more than one opt=... in the URI - the debug engine will always supply one based on // the options that it gets from VS, but the user can also explicitly specify it directly in the URI when doing // ptvsd attach (this is currently the only way to enable some flags when attaching, e.g. Django debugging). // ParseQueryString will automatically concat them all into a single value using commas. var queryParts = HttpUtility.ParseQueryString(uri.Query); debugOptions = queryParts[AD7Engine.DebugOptionsKey] ?? ""; } var stream = Connect(uri, warnAboutAuthenticationErrors); try { stream.Write(AttachCommandBytes); stream.WriteString(debugOptions); string attachResp = stream.ReadAsciiString(Accepted.Length); if (attachResp != Accepted) { throw new ConnectionException(ConnErrorMessages.RemoteAttachRejected); } int pid = stream.ReadInt32(); int langMajor = stream.ReadInt32(); int langMinor = stream.ReadInt32(); int langMicro = stream.ReadInt32(); var langVer = (PythonLanguageVersion)((langMajor << 8) | langMinor); if (!Enum.IsDefined(typeof(PythonLanguageVersion), langVer)) { langVer = PythonLanguageVersion.None; } var process = new PythonRemoteProcess(pid, uri, langVer); process.Connect(stream); stream = null; return process; } catch (IOException ex) { throw new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex); } finally { if (stream != null) { stream.Close(); } } }
public static PythonRemoteDebugProcess Connect(PythonRemoteDebugPort port) { PythonRemoteDebugProcess process = null; // Connect to the remote debugging server and obtain process information. If any errors occur, display an error dialog, and keep // trying for as long as user clicks "Retry". while (true) { Stream stream = null; ConnectionException connEx = null; try { // Process information is not sensitive, so ignore any SSL certificate errors, rather than bugging the user with warning dialogs. stream = PythonRemoteProcess.Connect(port.Uri, false); } catch (ConnectionException ex) { connEx = ex; } using (stream) { if (stream != null) { try { stream.Write(PythonRemoteProcess.InfoCommandBytes); int pid = stream.ReadInt32(); string exe = stream.ReadString(); string username = stream.ReadString(); string version = stream.ReadString(); process = new PythonRemoteDebugProcess(port, pid, exe, username, version); break; } catch (IOException ex) { connEx = new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex); } } if (connEx != null) { string errText; switch (connEx.Error) { case ConnErrorMessages.RemoteUnsupportedServer: errText = string.Format("Remote server at {0} is not a Python Tools for Visual Studio remote debugging server, or its version is not supported.", port.Uri); break; case ConnErrorMessages.RemoteSecretMismatch: errText = string.Format("Secret '{0}' did not match the server secret at {1}. Make sure that the secret is specified correctly in the Qualifier textbox, e.g. tcp://secret@localhost.", port.Uri.UserInfo, new UriBuilder(port.Uri) { UserName = null, Password = null }.Uri); break; case ConnErrorMessages.RemoteSslError: // User has already got a warning dialog and clicked "Cancel" on that, so no further prompts are needed. return(null); default: { // Azure uses HTTP 503 (Service Unavailable) to indicate that websocket connections are not supported. Show a special error message for that. var wsEx = connEx.InnerException as WebSocketException; if (wsEx != null) { var webEx = wsEx.InnerException as WebException; if (webEx != null) { var httpResponse = webEx.Response as HttpWebResponse; if (httpResponse != null && httpResponse.StatusCode == HttpStatusCode.ServiceUnavailable) { errText = string.Format("Could not connect to remote Python process at {0}. Make sure that web sockets are enabled for the corresponding web site in Azure portal.", port.Uri); break; } } } errText = string.Format("Could not connect to remote Python process at {0}. Make sure that the process is running, and has called ptvsd.enable_attach().", port.Uri); for (var ex = connEx.InnerException; ex != null; ex = ex.InnerException) { if (ex.InnerException == null) { errText += "\r\n\r\nAdditional information:\r\n" + ex.Message; } } break; } } DialogResult dlgRes = MessageBox.Show(errText, null, MessageBoxButtons.RetryCancel, MessageBoxIcon.Error); if (dlgRes != DialogResult.Retry) { break; } } } } return(process); }
public static async Task <PythonRemoteDebugProcess> ConnectAsync(PythonRemoteDebugPort port, TextWriter debugLog, CancellationToken ct) { PythonRemoteDebugProcess process = null; // Connect to the remote debugging server and obtain process information. If any errors occur, display an error dialog, and keep // trying for as long as user clicks "Retry". while (true) { DebugConnection debugConn = null; ConnectionException connEx = null; try { // Process information is not sensitive, so ignore any SSL certificate errors, rather than bugging the user with warning dialogs. debugConn = await PythonRemoteProcess.ConnectAsync(port.Uri, false, debugLog, ct); } catch (ConnectionException ex) { connEx = ex; } using (debugConn) { if (debugConn != null) { try { var response = await debugConn.SendRequestAsync(new LDP.RemoteDebuggerInfoRequest(), ct); process = new PythonRemoteDebugProcess(port, response.processId, response.executable, response.user, response.pythonVersion); break; } catch (IOException ex) { connEx = new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex); } catch (FailedRequestException ex) { connEx = new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex); } } if (connEx != null) { string errText; switch (connEx.Error) { case ConnErrorMessages.RemoteUnsupportedServer: errText = Strings.RemoteUnsupportedServer_Host.FormatUI(port.Uri); break; case ConnErrorMessages.RemoteSecretMismatch: errText = Strings.RemoteSecretMismatch_Host.FormatUI(new UriBuilder(port.Uri) { UserName = null, Password = null }.Uri); break; case ConnErrorMessages.RemoteSslError: // User has already got a warning dialog and clicked "Cancel" on that, so no further prompts are needed. return(null); default: { // Azure uses HTTP 503 (Service Unavailable) to indicate that websocket connections are not supported. Show a special error message for that. var wsEx = connEx.InnerException as WebSocketException; if (wsEx != null) { var webEx = wsEx.InnerException as WebException; if (webEx != null) { var httpResponse = webEx.Response as HttpWebResponse; if (httpResponse != null && httpResponse.StatusCode == HttpStatusCode.ServiceUnavailable) { errText = Strings.RemoteAzureServiceUnavailable_Host.FormatUI(port.Uri); break; } } } errText = Strings.RemoteServiceUnavailable_Host.FormatUI(port.Uri); for (var ex = connEx.InnerException; ex != null; ex = ex.InnerException) { if (ex.InnerException == null) { errText += "\r\n\r\n{0}\r\n{1}".FormatUI(Strings.AdditionalInformation, ex.Message); } } break; } } DialogResult dlgRes = MessageBox.Show(errText, Strings.ProductTitle, MessageBoxButtons.RetryCancel, MessageBoxIcon.Error); if (dlgRes != DialogResult.Retry) { break; } } } } return(process); }
public static PythonRemoteDebugProcess Connect(PythonRemoteDebugPort port) { PythonRemoteDebugProcess process = null; // Connect to the remote debugging server and obtain process information. If any errors occur, display an error dialog, and keep // trying for as long as user clicks "Retry". while (true) { Stream stream = null; ConnectionException connEx = null; try { // Process information is not sensitive, so ignore any SSL certificate errors, rather than bugging the user with warning dialogs. stream = PythonRemoteProcess.Connect(port.Uri, false); } catch (ConnectionException ex) { connEx = ex; } using (stream) { if (stream != null) { try { stream.Write(PythonRemoteProcess.InfoCommandBytes); int pid = stream.ReadInt32(); string exe = stream.ReadString(); string username = stream.ReadString(); string version = stream.ReadString(); process = new PythonRemoteDebugProcess(port, pid, exe, username, version); break; } catch (IOException ex) { connEx = new ConnectionException(ConnErrorMessages.RemoteNetworkError, ex); } } if (connEx != null) { string errText; switch (connEx.Error) { case ConnErrorMessages.RemoteUnsupportedServer: errText = Strings.RemoteUnsupportedServer_Host.FormatUI(port.Uri); break; case ConnErrorMessages.RemoteSecretMismatch: errText = Strings.RemoteSecretMismatch_Host.FormatUI(new UriBuilder(port.Uri) { UserName = null, Password = null }.Uri); break; case ConnErrorMessages.RemoteSslError: // User has already got a warning dialog and clicked "Cancel" on that, so no further prompts are needed. return(null); default: { // Azure uses HTTP 503 (Service Unavailable) to indicate that websocket connections are not supported. Show a special error message for that. var wsEx = connEx.InnerException as WebSocketException; if (wsEx != null) { var webEx = wsEx.InnerException as WebException; if (webEx != null) { var httpResponse = webEx.Response as HttpWebResponse; if (httpResponse != null && httpResponse.StatusCode == HttpStatusCode.ServiceUnavailable) { errText = Strings.RemoteAzureServiceUnavailable_Host.FormatUI(port.Uri); break; } } } errText = Strings.RemoteServiceUnavailable_Host.FormatUI(port.Uri); for (var ex = connEx.InnerException; ex != null; ex = ex.InnerException) { if (ex.InnerException == null) { errText += "\r\n\r\n{0}\r\n{1}".FormatUI(Strings.AdditionalInformation, ex.Message); } } break; } } DialogResult dlgRes = MessageBox.Show(errText, Strings.ProductTitle, MessageBoxButtons.RetryCancel, MessageBoxIcon.Error); if (dlgRes != DialogResult.Retry) { break; } } } } return(process); }