/// <summary> /// Removes a specified HTTP request from the requests queue (when it is completed). /// </summary> public virtual bool RemoveRequest(LongPollingRequest exchange) { if (null != exchange) { lock (_exchanges) { if (!_aborted) return _exchanges.Remove(exchange); // DEBUG //Debug.Print("The HTTP request was removed; Exchanges count: {0}", _exchanges.Count); } } return false; }
/// <summary> /// Removes a specified HTTP request from the requests queue (when it is completed). /// </summary> public virtual bool RemoveRequest(LongPollingRequest exchange) { if (null != exchange) { lock (_exchanges) { if (!_aborted) { return(_exchanges.Remove(exchange)); } // DEBUG //Debug.Print("The HTTP request was removed; Exchanges count: {0}", _exchanges.Count); } } return(false); }
/// <summary> /// Abort the request if the timer fires. /// </summary> private static void TimeoutCallback(object state, bool timedOut) { if (timedOut) { // DEBUG logger.Warn("HTTP Web request Timeout detected!"); LongPollingRequest exchange = state as LongPollingRequest; if (exchange != null) { exchange.Abort(); if (null != exchange._listener) { exchange._listener.OnExpire(exchange._messages); } } } }
/// <summary> /// Sends the specified messages to a Bayeux server asynchronously. /// </summary> /// <param name="listener">The listener used to process the request response.</param> /// <param name="messages">The list of messages will be sent in one HTTP request.</param> public override void Send(ITransportListener listener, params IMutableMessage[] messages) { if (messages == null || messages.Length == 0 || messages[0] == null) throw new ArgumentNullException("messages"); string url = this.Url; if (null == url) url = String.Empty; else url = url.Trim(); // Builds the request URL based on the message channel name Match uriMatch = uriRegex.Match(url); if (uriMatch.Success) { string afterPath = (uriMatch.Groups.Count > 7) ? uriMatch.Groups[7].Value : null; // Append message type into the URL ? if ((afterPath == null || afterPath.Trim().Length == 0) && messages.Length == 1 && messages[0].IsMeta) { string type = messages[0].Channel.Substring(Channel.Meta.Length); url = url.TrimEnd('\\', '/') + "/" + type.Trim('\\', '/'); } } try { // Creates a new HttpWebRequest object HttpWebRequest request = WebRequest.Create(new Uri(url, UriKind.RelativeOrAbsolute)) as HttpWebRequest; request.Method = WebRequestMethods.Http.Post; request.Accept = "application/json"; request.ContentType = request.Accept + ";charset=" + Encoding.UTF8.WebName; request.KeepAlive = true; request.AllowWriteStreamBuffering = true; // Is needed for KeepAlive request.AllowAutoRedirect = true; request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; request.Proxy = null; // Skips the proxy auto-detect step (~ 7s) // Setups HTTP request headers this.ApplyRequestHeaders(request); // Setups HTTP request cookies this.ApplyRequestCookies(request); // Calculates the HTTP request timeout (in milliseconds) int maxNetworkDelay = this.GetOption<int>(MaxNetworkDelayOption, request.Timeout); if (messages.Length == 1 && Channel.MetaConnect.Equals(messages[0].Channel, StringComparison.OrdinalIgnoreCase)) { IDictionary<string, object> advice = messages[0].Advice; if (advice == null) advice = _advice; object val; if (advice != null && advice.TryGetValue(Message.TimeoutField, out val)) { long timeout = ObjectConverter.ToPrimitive<long>(val, 0); if (timeout != 0) maxNetworkDelay += unchecked((int)timeout); } } request.Timeout = maxNetworkDelay; //if (null != _customize) _customize(request); // Creates a new HTTP Transport Exchange LongPollingRequest httpExchange; lock (_exchanges) { if (_aborted) throw new InvalidOperationException("The client transport has been aborted."); httpExchange = new LongPollingRequest(this, request, listener, messages); _exchanges.Add(httpExchange); } // Processes the HTTP request httpExchange.Send(); } catch (Exception ex) { if (listener != null) listener.OnException(ex, messages); else { // DEBUG Trace.TraceError("Failed to send messages:{0}{1}{0}--- via transport: {2}{0}{3}", Environment.NewLine, ObjectConverter.Serialize(messages), this.ToString(), ex.ToString()); } } }
private static void GetResponseCallback(IAsyncResult asyncResult) { LongPollingRequest exchange = asyncResult.AsyncState as LongPollingRequest; try { string responseString; HttpStatusCode responseStatus; // End the operation HttpWebResponse response; Exception error = null; try { response = exchange._request.EndGetResponse(asyncResult) as HttpWebResponse; } catch (WebException wex) { if (wex.Status == WebExceptionStatus.RequestCanceled) { throw; } response = wex.Response as HttpWebResponse; if (null == response) { throw; } error = wex; } using (response) { responseStatus = response.StatusCode; using (StreamReader streamRead = new StreamReader(response.GetResponseStream(), Encoding.UTF8, true)) { responseString = streamRead.ReadToEnd(); // DEBUG if (logger.IsDebugEnabled) { logger.DebugFormat(CultureInfo.InvariantCulture, "Received message(s): {0}", responseString); } } // Stores the transport Cookies to use for next requests if (response.Cookies != null && response.Cookies.Count > 0) { foreach (Cookie cookie in response.Cookies) { if (null != cookie && (!cookie.Discard || !cookie.Expired)) { exchange._transport.SetCookie(cookie); } } } } if (responseStatus != HttpStatusCode.OK) // TODO: error != null { if (null != exchange._listener) { exchange._listener.OnProtocolError(String.Format(CultureInfo.InvariantCulture, "Unexpected response {0}: {1}", (int)responseStatus, responseString), error, exchange._messages); } else { // DEBUG logger.Error(String.Format(CultureInfo.InvariantCulture, "Unexpected response {0}: {1}", (int)responseStatus, responseString), error); } } else if (responseString != null && (responseString = responseString.Trim()).Length > 0) { // TODO: responseString.Replace('"', '\'') IList <IMutableMessage> messages = DictionaryMessage.ParseMessages(responseString); // Backups the transport Timeout value (in milliseconds) to use for next requests foreach (IMutableMessage message in messages) { if (message != null && message.IsSuccessful && Channel.MetaConnect.Equals(message.Channel, StringComparison.OrdinalIgnoreCase)) { IDictionary <string, object> advice = message.Advice; object timeout; if (advice != null && advice.TryGetValue(Message.TimeoutField, out timeout) && timeout != null && timeout.ToString().Trim().Length > 0) { exchange._transport.Advice = advice; } } } if (null != exchange._listener) { // Fixes the received messages before processing string requestChannel = null; string requestUrl, baseUrl; foreach (IMutableMessage msg in messages) { if (String.IsNullOrEmpty(msg.Channel)) { if (null == requestChannel) { requestUrl = exchange._request.RequestUri.ToString(); // Absolute request URI baseUrl = exchange._transport.Url; baseUrl = (null == baseUrl) ? String.Empty : baseUrl.Trim(); if (requestUrl.StartsWith(baseUrl, StringComparison.OrdinalIgnoreCase)) { requestChannel = requestUrl.Substring(baseUrl.Length).Trim('\\', '/'); requestChannel = Channel.Meta.TrimEnd('\\', '/') + "/" + requestChannel; } else { requestChannel = String.Empty; } } if (!String.IsNullOrEmpty(requestChannel)) { msg.Channel = requestChannel; } } } exchange._listener.OnMessages(messages); } } else { if (null != exchange._listener) { exchange._listener.OnProtocolError(String.Format(CultureInfo.InvariantCulture, "Empty response (204) from URL: {0}", exchange._request.RequestUri), null, exchange._messages); } else { // DEBUG logger.ErrorFormat(CultureInfo.InvariantCulture, "Empty response (204) from URL: {0}", exchange._request.RequestUri); } } } catch (Exception ex) { if (null != exchange._listener && !exchange._aborted) { exchange._listener.OnException(ex, exchange._messages); } else { logger.Error(ex); // DEBUG } } finally { exchange._isSending = false; exchange._transport.RemoveRequest(exchange); } }
// From http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetrequeststream.aspx private static void GetRequestStreamCallback(IAsyncResult asyncResult) { LongPollingRequest exchange = asyncResult.AsyncState as LongPollingRequest; try { string content = ObjectConverter.Serialize(exchange._messages); // DEBUG //if (logger.IsDebugEnabled) // logger.DebugFormat(CultureInfo.InvariantCulture, "Sending message(s): {0}", content); // Convert the string into a byte array byte[] buffer = Encoding.UTF8.GetBytes(content); // End the operation using (Stream postStream = exchange._request.EndGetRequestStream(asyncResult)) { // Write to the request stream postStream.Write(buffer, 0, buffer.Length); } // On request committed if (null != exchange._listener) { exchange._listener.OnSending(exchange._messages); } int exchangeTimeout = exchange._request.Timeout; // TODO: Restore request timeout (default: 100 seconds) //exchange._request.Timeout = exchange._transport.GetOption<int>(ClientTransport.MaxNetworkDelayOption, 100000); // DEBUG if (logger.IsDebugEnabled) { logger.DebugFormat(CultureInfo.InvariantCulture, "Begin get response from URL: '{0}' with exchange timeout: {1}", exchange._request.RequestUri, exchangeTimeout); } // Start the asynchronous operation to get the response IAsyncResult result = exchange._request.BeginGetResponse(new AsyncCallback(GetResponseCallback), exchange); // This line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), exchange, exchangeTimeout, true); } catch (Exception ex) { exchange._isSending = false; // TODO: OnConnectException if (null != exchange._listener && !exchange._aborted) { exchange._listener.OnException(ex, exchange._messages); } else { logger.Error(ex); // DEBUG } exchange._transport.RemoveRequest(exchange); } }
/// <summary> /// Sends the specified messages to a Bayeux server asynchronously. /// </summary> /// <param name="listener">The listener used to process the request response.</param> /// <param name="messages">The list of messages will be sent in one HTTP request.</param> public override void Send(ITransportListener listener, params IMutableMessage[] messages) { if (messages == null || messages.Length == 0 || messages[0] == null) { throw new ArgumentNullException("messages"); } string url = this.Url; if (null == url) { url = String.Empty; } else { url = url.Trim(); } // Builds the request URL based on the message channel name Match uriMatch = uriRegex.Match(url); if (uriMatch.Success) { string afterPath = (uriMatch.Groups.Count > 7) ? uriMatch.Groups[7].Value : null; // Append message type into the URL ? if ((afterPath == null || afterPath.Trim().Length == 0) && messages.Length == 1 && messages[0].IsMeta) { string type = messages[0].Channel.Substring(Channel.Meta.Length); url = url.TrimEnd('\\', '/') + "/" + type.Trim('\\', '/'); } } try { // Creates a new HttpWebRequest object HttpWebRequest request = WebRequest.Create(new Uri(url, UriKind.RelativeOrAbsolute)) as HttpWebRequest; request.Method = WebRequestMethods.Http.Post; request.Accept = "application/json"; request.ContentType = request.Accept + ";charset=" + Encoding.UTF8.WebName; request.KeepAlive = true; request.AllowWriteStreamBuffering = true; // Is needed for KeepAlive request.AllowAutoRedirect = true; request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; request.Proxy = null; // Skips the proxy auto-detect step (~ 7s) // Setups HTTP request headers this.ApplyRequestHeaders(request); // Setups HTTP request cookies this.ApplyRequestCookies(request); // Calculates the HTTP request timeout (in milliseconds) int maxNetworkDelay = this.GetOption <int>(MaxNetworkDelayOption, request.Timeout); if (messages.Length == 1 && Channel.MetaConnect.Equals(messages[0].Channel, StringComparison.OrdinalIgnoreCase)) { IDictionary <string, object> advice = messages[0].Advice; if (advice == null) { advice = _advice; } object val; if (advice != null && advice.TryGetValue(Message.TimeoutField, out val)) { long timeout = ObjectConverter.ToPrimitive <long>(val, 0); if (timeout != 0) { maxNetworkDelay += unchecked ((int)timeout); } } } request.Timeout = maxNetworkDelay; //if (null != _customize) _customize(request); // Creates a new HTTP Transport Exchange LongPollingRequest httpExchange; lock (_exchanges) { if (_aborted) { throw new InvalidOperationException("The client transport has been aborted."); } httpExchange = new LongPollingRequest(this, request, listener, messages); _exchanges.Add(httpExchange); } // Processes the HTTP request httpExchange.Send(); } catch (Exception ex) { if (listener != null) { listener.OnException(ex, messages); } else { // DEBUG Trace.TraceError("Failed to send messages:{0}{1}{0}--- via transport: {2}{0}{3}", Environment.NewLine, ObjectConverter.Serialize(messages), this.ToString(), ex.ToString()); } } }