diff --git a/src/app/SharpRaven/Data/Requester.Net45.cs b/src/app/SharpRaven/Data/Requester.Net45.cs index cc2f0bdf..919101fd 100644 --- a/src/app/SharpRaven/Data/Requester.Net45.cs +++ b/src/app/SharpRaven/Data/Requester.Net45.cs @@ -81,6 +81,35 @@ public async Task RequestAsync() } } } + + /// + /// Sends the user feedback asynchronously to sentry + /// + /// An empty string if succesful, otherwise the server response + public async Task SendFeedbackAsync() + { + using (var s = await this.webRequest.GetRequestStreamAsync()) + { + using (var sw = new StreamWriter(s)) + { + await sw.WriteAsync(feedback.ToString()); + } + } + using (var wr = (HttpWebResponse)await this.webRequest.GetResponseAsync()) + { + using (var responseStream = wr.GetResponseStream()) + { + if (responseStream == null) + return null; + + using (var sr = new StreamReader(responseStream)) + { + var response = await sr.ReadToEndAsync(); + return response; + } + } + } + } } } diff --git a/src/app/SharpRaven/Data/Requester.cs b/src/app/SharpRaven/Data/Requester.cs index a4c7f4e4..38157f6b 100644 --- a/src/app/SharpRaven/Data/Requester.cs +++ b/src/app/SharpRaven/Data/Requester.cs @@ -49,10 +49,10 @@ public partial class Requester { private readonly RequestData data; private readonly JsonPacket packet; + private readonly SentryUserFeedback feedback; private readonly RavenClient ravenClient; private readonly HttpWebRequest webRequest; - /// /// Initializes a new instance of the class. /// @@ -70,13 +70,7 @@ internal Requester(JsonPacket packet, RavenClient ravenClient) this.packet = ravenClient.PreparePacket(packet); this.data = new RequestData(this); - this.webRequest = (HttpWebRequest)System.Net.WebRequest.Create(ravenClient.CurrentDsn.SentryUri); - this.webRequest.Timeout = (int)ravenClient.Timeout.TotalMilliseconds; - this.webRequest.ReadWriteTimeout = (int)ravenClient.Timeout.TotalMilliseconds; - this.webRequest.Method = "POST"; - this.webRequest.Accept = "application/json"; - this.webRequest.Headers.Add("X-Sentry-Auth", PacketBuilder.CreateAuthenticationHeader(ravenClient.CurrentDsn)); - this.webRequest.UserAgent = PacketBuilder.UserAgent; + this.webRequest = CreateWebRequest(ravenClient.CurrentDsn.SentryUri); if (ravenClient.Compression) { @@ -84,10 +78,49 @@ internal Requester(JsonPacket packet, RavenClient ravenClient) this.webRequest.AutomaticDecompression = DecompressionMethods.Deflate; this.webRequest.ContentType = "application/octet-stream"; } + else this.webRequest.ContentType = "application/json; charset=utf-8"; + + } + + /// + /// Initializes a new instance of the class. + /// + /// The to initialize with. + /// The to initialize with. + internal Requester(SentryUserFeedback feedback, RavenClient ravenClient) + { + if (feedback == null) + throw new ArgumentNullException("feedback"); + + if (ravenClient == null) + throw new ArgumentNullException("ravenClient"); + + this.ravenClient = ravenClient; + this.feedback = feedback; + + var feedbackString = string.Format("{0}?dsn={1}&{2}", + ravenClient.CurrentDsn.FeedbackUri, + ravenClient.CurrentDsn.Uri, + feedback.ToString()); + this.webRequest = CreateWebRequest(new Uri(feedbackString)); + this.webRequest.Referer = ravenClient.CurrentDsn.Uri.DnsSafeHost; + + this.webRequest.ContentType = "application/x-www-form-urlencoded"; } + internal HttpWebRequest CreateWebRequest(Uri uri) + { + var request = (HttpWebRequest)System.Net.WebRequest.Create(uri); + request.Timeout = (int)this.ravenClient.Timeout.TotalMilliseconds; + request.ReadWriteTimeout = (int)this.ravenClient.Timeout.TotalMilliseconds; + request.Method = "POST"; + request.Accept = "application/json"; + request.Headers.Add("X-Sentry-Auth", PacketBuilder.CreateAuthenticationHeader(this.ravenClient.CurrentDsn)); + request.UserAgent = PacketBuilder.UserAgent; + return request; + } /// /// Gets the . @@ -121,7 +154,6 @@ public HttpWebRequest WebRequest get { return this.webRequest; } } - /// /// Executes the HTTP request to Sentry. /// @@ -164,5 +196,34 @@ public string Request() } } } + + /// + /// Sends the user feedback to sentry + /// + /// An empty string if succesful, otherwise the server response + public string SendFeedback() + { + using (var s = this.webRequest.GetRequestStream()) + { + using (var sw = new StreamWriter(s)) + { + sw.Write(feedback.ToString()); + } + } + using (var wr = (HttpWebResponse)this.webRequest.GetResponse()) + { + using (var responseStream = wr.GetResponseStream()) + { + if (responseStream == null) + return null; + + using (var sr = new StreamReader(responseStream)) + { + var response = sr.ReadToEnd(); + return response; + } + } + } + } } } \ No newline at end of file diff --git a/src/app/SharpRaven/Data/SentryUserFeedback.cs b/src/app/SharpRaven/Data/SentryUserFeedback.cs new file mode 100644 index 00000000..917dab6b --- /dev/null +++ b/src/app/SharpRaven/Data/SentryUserFeedback.cs @@ -0,0 +1,92 @@ +#region License + +// Copyright (c) 2014 The Sentry Team and individual contributors. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted +// provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// 3. Neither the name of the Sentry nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +using System.Text; + +#endregion + +using System; +using System.Collections.Generic; +using System.Net; +#if net35 +using System.Web; +#endif + +namespace SharpRaven.Data +{ + /// + /// Represents the UserFeedback that is transmitted to Sentry + /// + public class SentryUserFeedback + { + /// + /// The name associated with this feedback + /// + public string Name { get; set; } + + /// + /// The email associated with this feedback + /// + public string Email { get; set; } + + /// + /// The comments associated with this feedback + /// + public string Comments { get; set; } + + /// + /// The event ID associated with this feedback + /// + public string EventID {get; set;} + + /// + /// Returns the url request string for this user feedback + /// + /// A that represents the url request string for this . + public override string ToString() + { + return string.Format("eventId={0}&name={1}&email={2}&comments={3}", +#if net35 + HttpUtility.UrlEncode(EventID), + HttpUtility.UrlEncode(Name), + HttpUtility.UrlEncode(Email), + HttpUtility.UrlEncode(Comments)); +#elif net40 + WebUtility.HtmlEncode(EventID), + WebUtility.HtmlEncode(Name), + WebUtility.HtmlEncode(Email), + WebUtility.HtmlEncode(Comments)); +#else + WebUtility.UrlEncode(EventID), + WebUtility.UrlEncode(Name), + WebUtility.UrlEncode(Email), + WebUtility.UrlEncode(Comments)); +#endif + } + } +} + diff --git a/src/app/SharpRaven/Dsn.cs b/src/app/SharpRaven/Dsn.cs index 4ee67a26..dacbca6f 100644 --- a/src/app/SharpRaven/Dsn.cs +++ b/src/app/SharpRaven/Dsn.cs @@ -45,6 +45,7 @@ public class Dsn private readonly string projectID; private readonly string publicKey; private readonly Uri sentryUri; + private readonly Uri feedbackUri; private readonly Uri uri; @@ -71,6 +72,12 @@ public Dsn(string dsn) Path, ProjectID); this.sentryUri = new Uri(sentryUriString); + var feedbackUriString = String.Format("{0}://{1}:{2}{3}/api/embed/error-page/", + this.uri.Scheme, + this.uri.DnsSafeHost, + Port, + Path); + this.feedbackUri = new Uri(feedbackUriString); } catch (Exception exception) { @@ -127,6 +134,14 @@ public Uri SentryUri get { return this.sentryUri; } } + /// + /// The Sentry Uri for sending user feedback + /// + public Uri FeedbackUri + { + get { return this.feedbackUri; } + } + /// /// Absolute Dsn Uri /// diff --git a/src/app/SharpRaven/RavenClient.Net45.cs b/src/app/SharpRaven/RavenClient.Net45.cs index 329189c9..108827af 100644 --- a/src/app/SharpRaven/RavenClient.Net45.cs +++ b/src/app/SharpRaven/RavenClient.Net45.cs @@ -153,6 +153,28 @@ protected virtual async Task SendAsync(JsonPacket packet) { return HandleException(exception, requester); } + } + + /// Sends the specified user feedback to Sentry + /// An empty string if succesful, otherwise the server response + /// The user feedback to send + public async Task SendUserFeedbackAsync(SentryUserFeedback feedback) + { + Requester requester = null; + + try + { + requester = new Requester(feedback, this); + + if (BeforeSend != null) + requester = BeforeSend(requester); + + return await requester.SendFeedbackAsync(); + } + catch (Exception exception) + { + return HandleException(exception, requester); + } } } } diff --git a/src/app/SharpRaven/RavenClient.cs b/src/app/SharpRaven/RavenClient.cs index adb48011..64c9abd0 100644 --- a/src/app/SharpRaven/RavenClient.cs +++ b/src/app/SharpRaven/RavenClient.cs @@ -230,6 +230,7 @@ public string Capture(SentryEvent @event) } + /// /// Captures the event. /// @@ -367,6 +368,28 @@ protected virtual string Send(JsonPacket packet) } } + /// Sends the specified user feedback to Sentry + /// An empty string if succesful, otherwise the server response + /// The user feedback to send + public string SendUserFeedback(SentryUserFeedback feedback) + { + Requester requester = null; + + try + { + requester = new Requester(feedback, this); + + if (BeforeSend != null) + requester = BeforeSend(requester); + + return requester.SendFeedback(); + } + catch (Exception exception) + { + return HandleException(exception, requester); + } + } + private string HandleException(Exception exception, Requester requester) { diff --git a/src/app/SharpRaven/SharpRaven.csproj b/src/app/SharpRaven/SharpRaven.csproj index 29b734d0..9b93c36a 100644 --- a/src/app/SharpRaven/SharpRaven.csproj +++ b/src/app/SharpRaven/SharpRaven.csproj @@ -140,6 +140,7 @@ +