/// <summary>
        /// Dispatches the request to each handler registered to receive notification of this request's method
        /// </summary>
        /// <param name="dispatcher"></param>
        /// <param name="request"></param>
        /// <param name="sender"></param>
        /// <param name="cancel"></param>
        private Delegate[] InternalDispatchRequest(object sender, ref HttpRequestCancelEventArgs e)
        {
            // look up the list of handlers for the specified hook point, and then look up the method in that list to
            Hashtable requestHandlers = this[HttpRequestHookPoints.BeforeHttpRuntimeProcessing];

            // receive the list of handlers that is handling callback notification for methods in that list
            HttpRequestCancelEventHandler handlers = requestHandlers[e.Request.Method] as HttpRequestCancelEventHandler;

            // there is a list of handlers waiting to be notified
            if (handlers == null)
            {
                return new Delegate[] {}
            }
            ;

            // extract the list of handlers to be notified when this method is received
            Delegate[] delegates = handlers.GetInvocationList();
            if (delegates == null)
            {
                return new Delegate[] {}
            }
            ;

            // enumerate each handler
            foreach (Delegate d in delegates)
            {
                try
                {
                    // notify the handler
                    ((HttpRequestCancelEventHandler)d)(sender, e);

                    // someone may have created a response that is ready to be sent for this event so no further processing is required
                    if (e.Response != null)
                    {
                        return(delegates);
                    }

                    // someone may have handled the request manually and there for this event is cancelled and no further processing is required
                    if (e.Cancel)
                    {
                        return(delegates);
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                }
            }

            return(delegates);
        }
Example #2
0
        /// <summary>
        /// Occurs when a request is received
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnRequestReceived(object sender, HttpRequestCancelEventArgs e)
        {
//			if (!_isServerSideConnection)
//			{
//				Debug.WriteLine(string.Format("User-Agent connection '{0}' auto-logging request '{1}'", _id.ToString(), HttpUtils.StripCRLF(e.Request.FirstLine)), MY_TRACE_CATEGORY);
//				Debug.WriteIf(_verbose, e.Request.ToString(false));
//			}
//			else
//			{
//				Debug.WriteLine(string.Format("Server-Side connection '{0}' auto-logging request '{1}'", _id.ToString(), HttpUtils.StripCRLF(e.Request.FirstLine)), MY_TRACE_CATEGORY);
//				Debug.WriteIf(_verbose, e.Request.ToString(false));
//			}

            // dispatch the request out to be handled
            if (_dispatcher != null)
            {
                _dispatcher.DispatchRequest(sender, ref e);
            }
            else
            {
                Debug.WriteLine(string.Format("Received a message, however there is no dispatcher available to handle the message for connection '{0}'.", _id.ToString()));
            }

            // did someone cancel the request?
            if (e.Cancel)
            {
                return;                 // do not send a response, some will have done this manually
            }

            /*
             * IMPORTANT!!! - We are providing a mechanism to override the default HTTP/1.1 specification's behaviour.
             * The specs state explicitly under all conditions a response must be sent to a request. We have certain scenarious where
             * we only need to send a request, no further processing is required as to the result of the request by the user-agent, so
             * the 'Reponse-Needed' header can be included to prevent the 'Server' from responding to the request.
             * */
            if (e.Request.ResponseNeeded)
            {
                // if there is a response prepared let's send it now
                HttpRequest  request  = e.Request;
                HttpResponse response = e.Response;

                // send a response to the request
                this.SendResponseToRequest(ref request, ref response);
            }
        }
		/// <summary>
		/// Occurs when a request is received
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected virtual void OnRequestReceived(object sender, HttpRequestCancelEventArgs e)
		{	
//			if (!_isServerSideConnection)
//			{
//				Debug.WriteLine(string.Format("User-Agent connection '{0}' auto-logging request '{1}'", _id.ToString(), HttpUtils.StripCRLF(e.Request.FirstLine)), MY_TRACE_CATEGORY);
//				Debug.WriteIf(_verbose, e.Request.ToString(false));
//			}
//			else
//			{
//				Debug.WriteLine(string.Format("Server-Side connection '{0}' auto-logging request '{1}'", _id.ToString(), HttpUtils.StripCRLF(e.Request.FirstLine)), MY_TRACE_CATEGORY);
//				Debug.WriteIf(_verbose, e.Request.ToString(false));
//			}

			// dispatch the request out to be handled
			if (_dispatcher != null)
				_dispatcher.DispatchRequest(sender, ref e);
            else
				Debug.WriteLine(string.Format("Received a message, however there is no dispatcher available to handle the message for connection '{0}'.", _id.ToString()));

			// did someone cancel the request?
			if (e.Cancel)
				return; // do not send a response, some will have done this manually

			/*
			 * IMPORTANT!!! - We are providing a mechanism to override the default HTTP/1.1 specification's behaviour.
			 * The specs state explicitly under all conditions a response must be sent to a request. We have certain scenarious where
			 * we only need to send a request, no further processing is required as to the result of the request by the user-agent, so
			 * the 'Reponse-Needed' header can be included to prevent the 'Server' from responding to the request.
			 * */ 			 
			if (e.Request.ResponseNeeded)
			{
				// if there is a response prepared let's send it now
				HttpRequest request = e.Request;
				HttpResponse response = e.Response;

				// send a response to the request
				this.SendResponseToRequest(ref request, ref response);
			}
		}
		/// <summary>
		/// Tries to receive data from the network on a background thread
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected virtual void OnReadFromSocket(object sender, BackgroundThreadStartEventArgs threadStartArgs) 
		{
			try 
			{	               
				// create a new message reader
				_messageReader = new HttpMessageReader();
				
				while(true) 
				{
					try 
					{			
//						if (!_isServerSideConnection)
//							Debug.WriteLine(string.Format("User-Agent connection '{0}' trying to read next incoming message from '{1}'", _id.ToString(), this.RemoteAddress.ToString()), MY_TRACE_CATEGORY);
//						else
//							Debug.WriteLine(string.Format("Server-Side connection '{0}' trying to read next incoming message from '{1}'", _id.ToString(), this.RemoteAddress.ToString()), MY_TRACE_CATEGORY);

						// read a single message
						HttpMessage message = null;
							
						// lock the reader
						lock(_messageReader)
						{
							// read a message
							message = _messageReader.Read(_socket, _stopEvent);
						}

						// what type of message is this ?						
						switch(message.Type)
						{
								/*
								 * process the request
								 * */
							case HttpMessageTypes.HttpRequest:
							{	
								// create a request event args
								HttpRequestCancelEventArgs e = new HttpRequestCancelEventArgs(new HttpRequest(message), false);					
								
								// process the request by dispatching it and then responding if need be
								this.OnRequestReceived(this, e);
								
								//								// next check the request to see if the connection should be closed after the response was sent
								//								if (HttpUtils.Contains(e.Request.Connection, HttpConnections.Close))
								//								{
								//									// yup, they wanted us to close the connection automatically so lets do that now
								//									this.Close();
								//									return;
								//								}
								break;
							}
								/*
								 * process the response
								 * */
							case HttpMessageTypes.HttpResponse:
							{
								this.OnResponseReceived(this, new HttpResponseEventArgs(new HttpResponse(message)));
								break;
							}
								/*
								 * an unknown message type
								 * */
							default:
							{	
								// hopefully this will never happen!
								Debug.WriteLine(string.Format("A message of unknown type was received from '{0}'...\n{1}", message));	
								break;
							}							
						};
					}
					catch(HttpMessageReaderAbortedException)
					{
						// the reader was aborted
					}
					catch(HttpConnectionClosedByPeerException) 
					{					
						/*
						* the remote host has closed the connection
						* */
						this.Close();
						return;
					}
					
					// see if we should stop receiving
					if (_stopEvent != null)
						if (_stopEvent.WaitOne(1, false)) 
						{
							/*
							* we have recieved a signal that we should stop receiving
							* and disconnect the current connection
							* */
							if (_disconnectOnStop)
								this.Close();
							return;
						}							
				}
												
			}
			catch(ThreadAbortException) 
			{
				/*
				 * the thread is aborting
				 * */
				if (_disconnectOnStop)
					this.Close();
			}
			catch(ObjectDisposedException) 
			{
				/*
				 * the connection has closed the socket
				 * */				
				this.Close();
			}
			catch(SocketException ex) 
			{
				// if the connection is reset, or a blocking call was cancelled with a call to cancelblockingcall
				if (ex.ErrorCode == (int)SocketErrors.WSAECONNRESET ||
					ex.ErrorCode == (int)SocketErrors.WSAEINTR) 
				{
					this.Close();
					return;
				}

				// notify that this connection has encountered an exception
				this.OnException(this, new ExceptionEventArgs(ex));
			}
			catch(Exception ex) 
			{
				// notify that this connection has encountered an exception
				this.OnException(this, new ExceptionEventArgs(ex));
			}
//			finally
//			{
//				Debug.WriteLineIf(!_isServerSideConnection, string.Format("*** exiting receiving thread loop for connection '{0}'", _id.ToString()), MY_TRACE_CATEGORY);
//			}
		}
Example #5
0
        /// <summary>
        /// Tries to receive data from the network on a background thread
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnReadFromSocket(object sender, BackgroundThreadStartEventArgs threadStartArgs)
        {
            try
            {
                // create a new message reader
                _messageReader = new HttpMessageReader();

                while (true)
                {
                    try
                    {
//						if (!_isServerSideConnection)
//							Debug.WriteLine(string.Format("User-Agent connection '{0}' trying to read next incoming message from '{1}'", _id.ToString(), this.RemoteAddress.ToString()), MY_TRACE_CATEGORY);
//						else
//							Debug.WriteLine(string.Format("Server-Side connection '{0}' trying to read next incoming message from '{1}'", _id.ToString(), this.RemoteAddress.ToString()), MY_TRACE_CATEGORY);

                        // read a single message
                        HttpMessage message = null;

                        // lock the reader
                        lock (_messageReader)
                        {
                            // read a message
                            message = _messageReader.Read(_socket, _stopEvent);
                        }

                        // what type of message is this ?
                        switch (message.Type)
                        {
                        /*
                         * process the request
                         * */
                        case HttpMessageTypes.HttpRequest:
                        {
                            // create a request event args
                            HttpRequestCancelEventArgs e = new HttpRequestCancelEventArgs(new HttpRequest(message), false);

                            // process the request by dispatching it and then responding if need be
                            this.OnRequestReceived(this, e);

                            //								// next check the request to see if the connection should be closed after the response was sent
                            //								if (HttpUtils.Contains(e.Request.Connection, HttpConnections.Close))
                            //								{
                            //									// yup, they wanted us to close the connection automatically so lets do that now
                            //									this.Close();
                            //									return;
                            //								}
                            break;
                        }

                        /*
                         * process the response
                         * */
                        case HttpMessageTypes.HttpResponse:
                        {
                            this.OnResponseReceived(this, new HttpResponseEventArgs(new HttpResponse(message)));
                            break;
                        }

                        /*
                         * an unknown message type
                         * */
                        default:
                        {
                            // hopefully this will never happen!
                            Debug.WriteLine(string.Format("A message of unknown type was received from '{0}'...\n{1}", message));
                            break;
                        }
                        }
                        ;
                    }
                    catch (HttpMessageReaderAbortedException)
                    {
                        // the reader was aborted
                    }
                    catch (HttpConnectionClosedByPeerException)
                    {
                        /*
                         * the remote host has closed the connection
                         * */
                        this.Close();
                        return;
                    }

                    // see if we should stop receiving
                    if (_stopEvent != null)
                    {
                        if (_stopEvent.WaitOne(1, false))
                        {
                            /*
                             * we have recieved a signal that we should stop receiving
                             * and disconnect the current connection
                             * */
                            if (_disconnectOnStop)
                            {
                                this.Close();
                            }
                            return;
                        }
                    }
                }
            }
            catch (ThreadAbortException)
            {
                /*
                 * the thread is aborting
                 * */
                if (_disconnectOnStop)
                {
                    this.Close();
                }
            }
            catch (ObjectDisposedException)
            {
                /*
                 * the connection has closed the socket
                 * */
                this.Close();
            }
            catch (SocketException ex)
            {
                // if the connection is reset, or a blocking call was cancelled with a call to cancelblockingcall
                if (ex.ErrorCode == (int)SocketErrors.WSAECONNRESET ||
                    ex.ErrorCode == (int)SocketErrors.WSAEINTR)
                {
                    this.Close();
                    return;
                }

                // notify that this connection has encountered an exception
                this.OnException(this, new ExceptionEventArgs(ex));
            }
            catch (Exception ex)
            {
                // notify that this connection has encountered an exception
                this.OnException(this, new ExceptionEventArgs(ex));
            }
//			finally
//			{
//				Debug.WriteLineIf(!_isServerSideConnection, string.Format("*** exiting receiving thread loop for connection '{0}'", _id.ToString()), MY_TRACE_CATEGORY);
//			}
        }
//		/// <summary>
//		/// Unregisters for notification for when the specified method is received in a HttpRequest
//		/// </summary>
//		/// <param name="method">The method notification was registered for</param>
//		/// <param name="onRequest">The callback to be notified when/if the method is received</param>
//		public void UnregisterForRequestMethodNotification(string method, HttpRequestEventHandler onRequest)
//		{
//			// we must have a valid method
//			HttpUtils.ValidateToken(@"method", method);
//
//			// and we must have a valid callback
//			if (onRequest == null)
//				throw new ArgumentNullException("onRequest");
//
//			// look up the list of handlers for the specified hook point, and then look up the method in that list to
//			Hashtable requestHandlers = this[HttpRequestHookPoints.AfterHttpRuntimeProcessing];
//
//			// receive the list of handlers that is handling callback notification for methods in that list
//			HttpRequestEventHandler handlers = requestHandlers[method] as HttpRequestEventHandler;
//
//			// if the handler list is null
//			if (handlers != null)
//				// add the handlers into the list by the method we're registering for
//				handlers = (HttpRequestEventHandler)Delegate.Remove(handlers, onRequest);
//
//			// if there are still some handlers, and the list is zero length, remove the list entirely
//			if (handlers != null)
//				if (handlers.GetInvocationList().Length == 0)
//				{
//					requestHandlers.Remove(method);
//					return;
//				}
//
//			// save the list of handlers for the next guy
//			requestHandlers[method] = handlers;
//		}

        /// <summary>
        /// Dispatches the HttpRequest to the registered handlers for processing. If no response is created or sent, then a default response will be prepared.
        /// </summary>
        /// <param name="dispatcher"></param>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void DispatchRequest(object sender, ref HttpRequestCancelEventArgs e)
        {
//			Debug.WriteLine(string.Format("Dispatching request '{0}'.", e.Request.Method));

            // internally dispatch the request to the registered handler(s) until someone responds to the request
            Delegate[] delegates = this.InternalDispatchRequest(sender, ref e);

            if (!e.Cancel && e.Response == null)
            {
                #region Asp Processing

                // if we have an asp host
                if (_aspHost != null)
                {
                    bool alreadyRetried = false;

RetryAspProcessing:

                    try
                    {
                        // use the asp host to process the request
                        _aspHost.ProcessRequest((HttpConnection)sender, ref e);
                    }
                    catch (AppDomainUnloadedException)
                    {
//						Debug.WriteLine(ex);

                        // it might have unloaded on us, so we can try once more
                        if (!alreadyRetried)
                        {
                            // recreate the host
                            this.CreateAspHost();
                            alreadyRetried = true;

                            // jump back and try again
                            goto RetryAspProcessing;
                        }
                    }
                }

                #endregion

                // after the asp processing, it might have already sent the response so watch out that it didn't cancel
                // the remaining processing we had to do
                if (e.Cancel)
                {
                    return;
                }

                // and finally if we still have no response for the request, let's fill in which ever is appropriate
                if (e.Response == null)
                {
                    // if there are no handlers that were registered for the request's method
                    if (delegates.Length == 0)
                    {
                        // then the method is not allowed
                        e.Response = new HttpResponse(new MethodNotAllowedStatus());
                        e.Response.SetBodyFromString(string.Format("405 - The '{0}' method is not allowed.\nThe request for the '{1}' resource cannot be processed.", e.Request.Method, e.Request.RequestUri), HttpUtils.Encoding, MIME.Text.Plain);
                    }
                    else
                    {
                        // resource not found (there was a handler but it didn't respond) so obviously the resource couldn't be found
                        e.Response = new HttpResponse(new NotFoundStatus());
                        e.Response.SetBodyFromString(string.Format("404 - The resource '{0}' could not be found.", e.Request.RequestUri), HttpUtils.Encoding, MIME.Text.Plain);
                    }
                }
            }
        }
		/// <summary>
		/// Dispatches the request to each handler registered to receive notification of this request's method
		/// </summary>
		/// <param name="dispatcher"></param>
		/// <param name="request"></param>
		/// <param name="sender"></param>
		/// <param name="cancel"></param>
		private Delegate[] InternalDispatchRequest(object sender, ref HttpRequestCancelEventArgs e)
		{
			// look up the list of handlers for the specified hook point, and then look up the method in that list to 
			Hashtable requestHandlers = this[HttpRequestHookPoints.BeforeHttpRuntimeProcessing];

			// receive the list of handlers that is handling callback notification for methods in that list
			HttpRequestCancelEventHandler handlers = requestHandlers[e.Request.Method] as HttpRequestCancelEventHandler;

			// there is a list of handlers waiting to be notified
			if (handlers == null)				
				return new Delegate[] {};
						
			// extract the list of handlers to be notified when this method is received
			Delegate[] delegates = handlers.GetInvocationList();
			if (delegates == null)
				return new Delegate[] {};
									
			// enumerate each handler
			foreach(Delegate d in delegates)
			{
				try
				{
					// notify the handler
					((HttpRequestCancelEventHandler)d)(sender, e);

					// someone may have created a response that is ready to be sent for this event so no further processing is required
					if (e.Response != null)
						return delegates;					

					// someone may have handled the request manually and there for this event is cancelled and no further processing is required
					if (e.Cancel)					
						return delegates;										
				}
				catch(Exception ex)
				{
					Debug.WriteLine(ex);
				}
			}

			return delegates;
		}
//		/// <summary>
//		/// Unregisters for notification for when the specified method is received in a HttpRequest
//		/// </summary>
//		/// <param name="method">The method notification was registered for</param>
//		/// <param name="onRequest">The callback to be notified when/if the method is received</param>
//		public void UnregisterForRequestMethodNotification(string method, HttpRequestEventHandler onRequest)
//		{
//			// we must have a valid method
//			HttpUtils.ValidateToken(@"method", method);	
//			
//			// and we must have a valid callback
//			if (onRequest == null)
//				throw new ArgumentNullException("onRequest");
//
//			// look up the list of handlers for the specified hook point, and then look up the method in that list to 
//			Hashtable requestHandlers = this[HttpRequestHookPoints.AfterHttpRuntimeProcessing];
//
//			// receive the list of handlers that is handling callback notification for methods in that list
//			HttpRequestEventHandler handlers = requestHandlers[method] as HttpRequestEventHandler;
//
//			// if the handler list is null
//			if (handlers != null)
//				// add the handlers into the list by the method we're registering for
//				handlers = (HttpRequestEventHandler)Delegate.Remove(handlers, onRequest);
//
//			// if there are still some handlers, and the list is zero length, remove the list entirely
//			if (handlers != null)
//				if (handlers.GetInvocationList().Length == 0)
//				{
//					requestHandlers.Remove(method);
//					return;
//				}
//			
//			// save the list of handlers for the next guy
//			requestHandlers[method] = handlers;
//		}

		/// <summary>
		/// Dispatches the HttpRequest to the registered handlers for processing. If no response is created or sent, then a default response will be prepared.
		/// </summary>
		/// <param name="dispatcher"></param>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		public void DispatchRequest(object sender, ref HttpRequestCancelEventArgs e)
		{
//			Debug.WriteLine(string.Format("Dispatching request '{0}'.", e.Request.Method));

			// internally dispatch the request to the registered handler(s) until someone responds to the request
			Delegate[] delegates = this.InternalDispatchRequest(sender, ref e);
						
			if (!e.Cancel && e.Response == null)
			{			
				#region Asp Processing

				// if we have an asp host
				if (_aspHost != null)
				{
					bool alreadyRetried = false;
				
				RetryAspProcessing:
				
					try
					{
						// use the asp host to process the request
						_aspHost.ProcessRequest((HttpConnection)sender, ref e);
					}
					catch(AppDomainUnloadedException)
					{						
//						Debug.WriteLine(ex);

						// it might have unloaded on us, so we can try once more
						if (!alreadyRetried)
						{
							// recreate the host
							this.CreateAspHost();
							alreadyRetried = true;

							// jump back and try again
							goto RetryAspProcessing;
						}
					}
				}

				#endregion

				// after the asp processing, it might have already sent the response so watch out that it didn't cancel 
				// the remaining processing we had to do
				if (e.Cancel)
					return;

				// and finally if we still have no response for the request, let's fill in which ever is appropriate
				if (e.Response == null)
				{
					// if there are no handlers that were registered for the request's method
					if (delegates.Length == 0)
					{
						// then the method is not allowed
						e.Response = new HttpResponse(new MethodNotAllowedStatus());
						e.Response.SetBodyFromString(string.Format("405 - The '{0}' method is not allowed.\nThe request for the '{1}' resource cannot be processed.", e.Request.Method, e.Request.RequestUri), HttpUtils.Encoding, MIME.Text.Plain);
					}
					else
					{
						// resource not found (there was a handler but it didn't respond) so obviously the resource couldn't be found
						e.Response = new HttpResponse(new NotFoundStatus());
						e.Response.SetBodyFromString(string.Format("404 - The resource '{0}' could not be found.", e.Request.RequestUri), HttpUtils.Encoding, MIME.Text.Plain);
					}
				}
			}			
		}