Merge pull request #463 from strawd/concurrent-requests
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels.Http / HttpReplyChannel.cs
index 0770e6007dbfaf60c0fc5f2bedbd4824688586f5..03e7cad1f1c4f7eff0afaab6e7c41ebd1801f848 100644 (file)
 using System;
 using System.Collections.Generic;
 using System.Collections.Specialized;
+using System.IdentityModel.Selectors;
+using System.IdentityModel.Tokens;
 using System.IO;
 using System.Net;
 using System.ServiceModel;
+using System.ServiceModel.Security;
 using System.Text;
 using System.Threading;
 
@@ -40,11 +43,22 @@ namespace System.ServiceModel.Channels.Http
        {
                HttpChannelListener<IReplyChannel> source;
                RequestContext reqctx;
+               SecurityTokenAuthenticator security_token_authenticator;
+               SecurityTokenResolver security_token_resolver;
 
                public HttpReplyChannel (HttpChannelListener<IReplyChannel> listener)
                        : base (listener)
                {
                        this.source = listener;
+
+                       if (listener.SecurityTokenManager != null) {
+                               var str = new SecurityTokenRequirement () { TokenType = SecurityTokenTypes.UserName };
+                               security_token_authenticator = listener.SecurityTokenManager.CreateSecurityTokenAuthenticator (str, out security_token_resolver);
+                       }
+               }
+
+               internal HttpChannelListener<IReplyChannel> Source {
+                       get { return source; }
                }
 
                public MessageEncoder Encoder {
@@ -78,8 +92,8 @@ namespace System.ServiceModel.Channels.Http
                        AbortConnections (timeout);
                        // FIXME: this wait is sort of hack (because it should not be required), but without it some tests are blocked.
                        // This hack even had better be moved to base.CancelAsync().
-                       if (CurrentAsyncResult != null)
-                               CurrentAsyncResult.AsyncWaitHandle.WaitOne (TimeSpan.FromMilliseconds (300));
+//                     if (CurrentAsyncResult != null)
+//                             CurrentAsyncResult.AsyncWaitHandle.WaitOne (TimeSpan.FromMilliseconds (300));
                        return base.CancelAsync (timeout);
                }
 
@@ -139,20 +153,36 @@ namespace System.ServiceModel.Channels.Http
                        if (ctxi == null)
                                return true; // returning true, yet context is null. This happens at closing phase.
 
+                       if (source.Source.AuthenticationScheme != AuthenticationSchemes.Anonymous) {
+                               if (security_token_authenticator != null)
+                                       // FIXME: use return value?
+                                       try {
+                                               security_token_authenticator.ValidateToken (new UserNameSecurityToken (ctxi.User, ctxi.Password));
+                                       } catch (Exception) {
+                                               ctxi.ReturnUnauthorized ();
+                                       }
+                               else {
+                                       ctxi.ReturnUnauthorized ();
+                               }
+                       }
+
                        Message msg = null;
 
-                       if (ctxi.Request.HttpMethod == "POST") {
+                       if (ctxi.Request.HttpMethod == "POST")
                                msg = CreatePostMessage (ctxi);
-                               if (msg == null)
-                                       return false;
-                       } else if (ctxi.Request.HttpMethod == "GET")
+                       else if (ctxi.Request.HttpMethod == "GET")
                                msg = Message.CreateMessage (MessageVersion.None, null); // HTTP GET-based request
 
+                       if (msg == null)
+                               return false;
+
                        if (msg.Headers.To == null)
                                msg.Headers.To = ctxi.Request.Url;
                        msg.Properties.Add ("Via", LocalAddress.Uri);
                        msg.Properties.Add (HttpRequestMessageProperty.Name, CreateRequestProperty (ctxi));
 
+                       Logger.LogMessage (MessageLogSourceKind.TransportReceive, ref msg, source.Source.MaxReceivedMessageSize);
+
                        context = new HttpRequestContext (this, ctxi, msg);
                        reqctx = context;
                        return true;
@@ -177,8 +207,29 @@ namespace System.ServiceModel.Channels.Http
                        // FIXME: supply maxSizeOfHeaders.
                        int maxSizeOfHeaders = 0x10000;
 
+#if false // FIXME: enable it, once duplex callback test gets passed.
+                       Stream stream = ctxi.Request.InputStream;
+                       if (source.Source.TransferMode == TransferMode.Buffered) {
+                               if (ctxi.Request.ContentLength64 <= 0)
+                                       throw new ArgumentException ("This HTTP channel is configured to use buffered mode, and thus expects Content-Length sent to the listener");
+                               long size = 0;
+                               var ms = new MemoryStream ();
+                               var buf = new byte [0x1000];
+                               while (size < ctxi.Request.ContentLength64) {
+                                       if ((size += stream.Read (buf, 0, 0x1000)) > source.Source.MaxBufferSize)
+                                               throw new QuotaExceededException ("Message quota exceeded");
+                                       ms.Write (buf, 0, (int) (size - ms.Length));
+                               }
+                               ms.Position = 0;
+                               stream = ms;
+                       }
+
+                       var msg = Encoder.ReadMessage (
+                               stream, maxSizeOfHeaders, ctxi.Request.ContentType);
+#else
                        var msg = Encoder.ReadMessage (
                                ctxi.Request.InputStream, maxSizeOfHeaders, ctxi.Request.ContentType);
+#endif
 
                        if (MessageVersion.Envelope.Equals (EnvelopeVersion.Soap11) ||
                            MessageVersion.Addressing.Equals (AddressingVersion.None)) {
@@ -189,6 +240,7 @@ namespace System.ServiceModel.Channels.Http
                                        msg.Headers.Action = action;
                                }
                        }
+                       msg.Properties.Add (RemoteEndpointMessageProperty.Name, new RemoteEndpointMessageProperty (ctxi.Request.ClientIPAddress, ctxi.Request.ClientPort));
 
                        return msg;
                }