/// <summary>
 /// Closes the stream attached to this listener context.
 /// </summary>
 public void Close(int lingerValue)
 {
     try
     {
         // Close the underlying stream
         if (m_clientOutputStream != null)
         {
             try
             {
                 if (m_clientOutputStream.m_Socket != null)
                 {
                     m_clientOutputStream.m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerValue);
                 }
             }
             catch {}
             m_clientOutputStream.Dispose();
             m_clientOutputStream = null;
         }
         if (m_clientInputStream != null)
         {
             m_clientInputStream.Dispose();
             m_clientInputStream = null;
         }
     }
     catch
     {
     }
 }
Exemplo n.º 2
0
        public Stream CloneStream()
        {
            InputNetworkStreamWrapper clone = this.MemberwiseClone() as InputNetworkStreamWrapper;

            clone.m_isClone = true;

            return(clone);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Constructs a HttpListenerRequest is created by HttpListenerContext.
        /// </summary>
        /// <param name="clientStream">Network stream to the client.</param>
        /// <param name="maxHeaderLen">TBD</param>
        internal HttpListenerRequest(InputNetworkStreamWrapper clientStream, int maxHeaderLen)
        {
            this.m_clientStream = clientStream;

            // maxHeaderLen is in kilobytes (Desktop designer decided so). If -1 just maximum integer value
            this.m_maxResponseHeadersLen = maxHeaderLen == -1 ? 0x7FFFFFFF : maxHeaderLen * 1024;
            // If not set, default for content length is -1
            this.m_contentLength = -1;
        }
        /// <summary>
        /// Closes a response stream, if present.
        /// </summary>
        /// <param name="disposing">Not used.</param>
        protected override void Dispose(bool disposing)
        {
            if (m_responseStream != null)
            {
                bool closeConnection = true;
                if (m_httpWebRequest.KeepAlive)
                {
                    string connValue = null;

                    // Check if server have sent use "Connection:Close"
                    if (m_httpResponseHeaders != null)
                    {
                        connValue = m_httpResponseHeaders[HttpKnownHeaderNames.Connection];
                    }

                    // If server had not send this header or value is not "close", then we keep connection.
                    closeConnection = connValue == null || connValue.ToLower() == HttpKnownHeaderValues.close;

                    // Add new socket and port used to connect to the list of sockets.
                    // Save connected socket and Destination IP End Point, so it can be used next time.
                    // But first we need to validate that this socket is already not in the list. We do not want same socket to be twice in the list.
                    lock (HttpWebRequest.m_ConnectedStreams)
                    {
                        // If it is not in the list - Add it
                        if (closeConnection)
                        {
                            if (HttpWebRequest.m_ConnectedStreams.Contains(m_responseStream))
                            {
                                // Either KeepAlive was not set or server requested closing connection.
                                HttpWebRequest.m_ConnectedStreams.Remove(m_responseStream);
                            }

                            // Closing connection socket.
                            m_responseStream.Dispose();
                        }
                        else
                        {
                            m_responseStream.ReleaseStream();
                        }
                    }
                }

                // Set flag that we already completed work on this stream.
                m_responseStream = null;
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Closes the stream attached to this listener context.
        /// </summary>
        public void Close(int lingerValue)
        {
            try
            {
                if (this.m_clientOutputStream != null)
                {
                    try
                    {
                        if (this.m_clientOutputStream.m_Socket != null)
                        {
                            this.m_clientOutputStream.m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerValue);
                        }
                    }
                    catch {}
                }

                if (this.m_ResponseToClient != null)
                {
                    this.m_ResponseToClient.Close();
                    this.m_ResponseToClient = null;
                }

                // Close the underlying stream
                if (this.m_clientOutputStream != null)
                {
                    this.m_clientOutputStream.Dispose();
                    this.m_clientOutputStream = null;
                }

                if (this.m_clientInputStream != null)
                {
                    this.m_clientInputStream.Dispose();
                    this.m_clientInputStream = null;
                }
            }
            catch
            {
            }
        }
        /// <summary>
        /// Internal constructor, used each time client connects.
        /// </summary>
        /// <param name="clientStream">The stream that is connected to the client. A stream is needed, to
        /// provide information about the connected client.
        /// See also the <see cref="System.Net.HttpListenerRequest"/> class.
        /// </param>
        /// <param name="httpListener">TBD</param>
        internal HttpListenerContext(OutputNetworkStreamWrapper clientStream, HttpListener httpListener)
        {
            // Saves the stream.
            m_clientOutputStream = clientStream;

            // Input stream does not own socket.
            m_clientInputStream = new InputNetworkStreamWrapper(clientStream.m_Stream, clientStream.m_Socket, false, null);

            // Constructs request and response classes.
            m_ClientRequest = new HttpListenerRequest(m_clientInputStream, httpListener.m_maxResponseHeadersLen);

            // Closing reponse to client causes removal from clientSocketsList.
            // Thus we need to pass clientSocketsList to client response.
            m_ResponseToClient = new HttpListenerResponse(m_clientOutputStream, httpListener);

            // There is incoming connection HTTP connection. Add new Socket to the list of connected sockets
            // The socket is removed from this array after correponding HttpListenerResponse is closed.
            httpListener.AddClientStream(m_clientOutputStream);

            // Set flag that HTTP request was not parsed yet.
            // It will be parsed on first access to m_ClientRequest or m_ResponseToClient
            m_IsHTTPRequestParsed = false;
        }
        /// <summary>
        /// Internal constructor, used each time client connects.
        /// </summary>
        /// <param name="clientStream">The stream that is connected to the client. A stream is needed, to
        /// provide information about the connected client.
        /// See also the <see cref="System.Net.HttpListenerRequest"/> class.
        /// </param>
        /// <param name="httpListener">TBD</param>
        internal HttpListenerContext(OutputNetworkStreamWrapper clientStream, HttpListener httpListener)
        {
            // Saves the stream.
            m_clientOutputStream = clientStream;

            // Input stream does not own socket.
            m_clientInputStream = new InputNetworkStreamWrapper(clientStream.m_Stream, clientStream.m_Socket, false, null);

            // Constructs request and response classes.
            m_ClientRequest = new HttpListenerRequest(m_clientInputStream, httpListener.m_maxResponseHeadersLen);

            // Closing reponse to client causes removal from clientSocketsList.
            // Thus we need to pass clientSocketsList to client response.
            m_ResponseToClient = new HttpListenerResponse(m_clientOutputStream, httpListener);

            // There is incoming connection HTTP connection. Add new Socket to the list of connected sockets
            // The socket is removed from this array after correponding HttpListenerResponse is closed.
            httpListener.AddClientStream(m_clientOutputStream);

            // Set flag that HTTP request was not parsed yet.
            // It will be parsed on first access to m_ClientRequest or m_ResponseToClient
            m_IsHTTPRequestParsed = false;
        }
        /// <summary>
        /// Constructs a HttpListenerRequest is created by HttpListenerContext.
        /// </summary>
        /// <param name="clientStream">Network stream to the client.</param>
        /// <param name="maxHeaderLen">TBD</param>
        internal HttpListenerRequest(InputNetworkStreamWrapper clientStream, int maxHeaderLen)
        {
            m_clientStream = clientStream;

            // maxHeaderLen is in kilobytes (Desktop designer decided so). If -1 just maximum integer value
            m_maxResponseHeadersLen = maxHeaderLen == -1 ? 0x7FFFFFFF : maxHeaderLen * 1024;
            // If not set, default for content length is -1
            m_contentLength = -1;
        }
 /// <summary>
 /// Sets the response stream.
 /// </summary>
 /// <param name="stream"></param>
 /// <remarks>
 /// Used internally during creation of HttpWebResponse.
 /// </remarks>
 internal void SetResponseStream(InputNetworkStreamWrapper stream)
 {
     m_responseStream = stream;
 }
        /// <summary>
        /// Reads and parses HTTP response from server.
        /// After return of function HTTP response is read.
        /// </summary>
        /// <param name="inStream">Network stream connected to server.</param>
        /// <param name="defaultKeepAlive">TBD</param>
        /// <returns>CoreResponseData that describes server response.</returns>
        private CoreResponseData ParseHTTPResponse(InputNetworkStreamWrapper inStream, bool defaultKeepAlive)
        {
            // CoreResponseData keeps all the information of the response.
            CoreResponseData ret = new CoreResponseData();
            // maximumHeadersLength is maximum total length of http header. Basically this is amount
            // of memory used for headers.
            int headersLength = m_maxResponseHeadersLen == -1 ? 0x7FFFFFFF : m_maxResponseHeadersLen * 1024;

            ret.m_shouldClose = !defaultKeepAlive;
            // Parse the request line.
            string line = inStream.Read_HTTP_Line(maxHTTPLineLength).Trim();

            // Cutoff white spaces
            int currentOffset = 0;
            for (; currentOffset < line.Length && ' ' != line[currentOffset]; ++currentOffset) ;

            // find HTTP version, read http/1.x
            string httpVersionString = line.Substring(0, currentOffset).ToLower();
            if (httpVersionString.Equals("http/1.1"))
            {
                ret.m_version = HttpVersion.Version11;
            }
            else if (httpVersionString.Equals("http/1.0"))
            {
                ret.m_version = HttpVersion.Version10;
            }
            else
            {
                ret.m_status = WebExceptionStatus.ServerProtocolViolation;
                ret.m_exceptionMessage = "Unknown http version: " + httpVersionString;
                return ret;
            }

            //advance to the status code
            for (; currentOffset < line.Length && ' ' == line[currentOffset]; ++currentOffset) ;

            // Read the status code
            int codeStart = currentOffset;
            for (; currentOffset < line.Length && ' ' != line[currentOffset]; ++currentOffset) ;
            int statusCode = -1;
            try
            {
                string statusCodeStr =
                    line.Substring(codeStart,
                                    currentOffset - codeStart);
                statusCode = Convert.ToInt32(statusCodeStr);
            }
            catch (Exception e)
            {
                ret.m_status = WebExceptionStatus.ServerProtocolViolation;
                ret.m_exceptionMessage = "Missing status code in HTTP reply";
                ret.m_innerException = e;
                return ret;
            }

            // If we get here - status code should be read.
            ret.m_statusCode = statusCode;

            // Advance to the status message.  The message is optional
            for (; currentOffset < line.Length && ' ' != line[currentOffset]; ++currentOffset) ;
            ret.m_statusDescription = line.Substring(currentOffset);

            ret.m_headers = new WebHeaderCollection(true);
            ret.m_chunked = false;
            ret.m_contentLength = -1;

            while ((line = inStream.Read_HTTP_Header(maxHTTPLineLength)).Length > 0)
            {
                // line.Length is used for the header. Substruct it.
                headersLength -= line.Length;
                // If total length used for header is exceeded, we break
                if (headersLength < 0)
                {
                    ret.m_status = WebExceptionStatus.ServerProtocolViolation;
                    ret.m_exceptionMessage = "Headers size exceed limit";
                    return ret;
                }

                // Now parse the header.
                int sepIdx = line.IndexOf(':');
                if (sepIdx == -1)
                {
                    ret.m_status = WebExceptionStatus.ServerProtocolViolation;
                    ret.m_exceptionMessage = "Illegal header format: " + line;
                    return ret;
                }

                string headerName = line.Substring(0, sepIdx);
                string headerValue = line.Substring(sepIdx + 1).TrimStart(null);
                string matchableHeaderName = headerName.ToLower();

                ret.m_headers.AddInternal(headerName, headerValue);
                if (matchableHeaderName.Equals("content-length"))
                {
                    try
                    {
                        ret.m_contentLength = Convert.ToInt32(headerValue);

                        // set the response stream length for the input stream, so that an EOF will be read
                        // if the caller tries to read base the response content length
                        inStream.m_BytesLeftInResponse = ret.m_contentLength;
                    }
                    catch (Exception e)
                    {
                        ret.m_status =
                            WebExceptionStatus.ServerProtocolViolation;
                        ret.m_exceptionMessage = "Content length NAN: " + headerValue;
                        ret.m_innerException = e;
                        return ret;
                    }
                }
                else if (matchableHeaderName.Equals("transfer-encoding"))
                {
                    if (headerValue.ToLower().IndexOf("chunked") != -1)
                    {
                        ret.m_chunked = true;
                    }
                }
                else if (matchableHeaderName.Equals("connection"))
                {
                    if (headerValue.ToLower().IndexOf(HttpKnownHeaderValues.close) != -1)
                    {
                        ret.m_shouldClose = true;
                    }
                }
            }

            return ret;
        }
        /// <summary>
        /// Submits request to the WEB server.
        /// </summary>
        private void SubmitRequest()
        {
            // We have connected socket. Create request stream
            // If proxy is set - connect to proxy server.
            if (m_proxy == null)
            {   // Direct connection to target server.
                m_requestStream = EstablishConnection(m_originalUrl, m_originalUrl);
            }
            else // Connection through proxy. We create network stream connected to proxy
            {
                Uri proxyUri = m_proxy.GetProxy(m_originalUrl);

                if (m_originalUrl.Scheme == "https")
                {
                    // For HTTPs we still need to know the target name to decide on persistent connection.
                    m_requestStream = EstablishConnection(proxyUri, m_originalUrl);
                }
                else
                {
                    // For normal HTTP all requests go to proxy
                    m_requestStream = EstablishConnection(proxyUri, proxyUri);
                }
            }

            // We have connected stream. Set the timeout from HttpWebRequest
            m_requestStream.WriteTimeout = m_readWriteTimeout;
            m_requestStream.ReadTimeout = m_readWriteTimeout;

            // Now we need to write headers. First we update headers.
            PrepareHeaders();

            // Now send request string and headers.
            byte[] dataToSend = GetHTTPRequestData();

#if DEBUG   // In debug mode print the request. It helps a lot to troubleshoot the issues.
            int byteUsed, charUsed;
            bool completed = false;
            char[] charBuf = new char[dataToSend.Length];
            UTF8decoder.Convert(dataToSend, 0, dataToSend.Length, charBuf, 0, charBuf.Length, true, out byteUsed, out charUsed, out completed);
            string strSend = new string(charBuf);
            Debug.Print(strSend);
#endif
            // Writes this data to the network stream.
            m_requestStream.Write(dataToSend, 0, dataToSend.Length);
            m_requestSent = true;
        }
        /// <summary>
        /// Returns network stream connected to server. It could be a proxy or a
        /// real server Uri.
        /// </summary>
        /// <param name="proxyServer">Uri that describes the proxy server.</param>
        /// <param name="targetServer">Uri that describes the target (real) server.</param>
        /// <returns>Nerwork stream connected to server.</returns>
        private InputNetworkStreamWrapper EstablishConnection(Uri proxyServer, Uri targetServer)
        {
            InputNetworkStreamWrapper retStream = null;

            // Create a socket and set reuse true.
            // But before creating new socket we look in the list of existing sockets. If socket for this host already
            // exist - use it. No need to create new socket.
            string remoteServer = targetServer.Host + ":" + targetServer.Port;
            lock (m_ConnectedStreams)
            {
                ArrayList removeStreamList = new ArrayList();

                for (int i = 0; i < m_ConnectedStreams.Count; i++)
                {
                    InputNetworkStreamWrapper inputStream = (InputNetworkStreamWrapper)m_ConnectedStreams[i];

                    if (inputStream.m_rmAddrAndPort == remoteServer && !inputStream.m_InUse)
                    {
                        // Re-use the connected socket.
                        // But first we need to know that socket is not closed.
                        try
                        {
                            // If socket is closed ( from this or other side ) the call throws exception.
                            if (inputStream.m_Socket.Poll(1, SelectMode.SelectWrite))
                            {
                                // No exception, good we can condtinue and re-use connected stream.

                                // Control flow returning here means persistent connection actually works. 
                                inputStream.m_InUse = true;
                                inputStream.m_lastUsed = DateTime.Now;

                                retStream = inputStream;
                                break;
                            }
                            else
                            {
                                removeStreamList.Add(inputStream);
                            }

                        }
                        catch (Exception)
                        {
                            removeStreamList.Add(inputStream);
                        }

                    }
                }

                for (int i = 0; i < removeStreamList.Count; i++)
                {
                    InputNetworkStreamWrapper removeStream = (InputNetworkStreamWrapper)removeStreamList[i];

                    // Means socket was closed. Remove it from the list.
                    m_ConnectedStreams.Remove(removeStream);

                    removeStream.Dispose();
                }
            }

            if (retStream == null)
            {
                // Existing connection did not worked. Need to establish new one.
                IPAddress address = null;
                UriHostNameType hostNameType = proxyServer.HostNameType;
                if (hostNameType == UriHostNameType.IPv4)
                {
                    address = IPAddress.Parse(proxyServer.Host);
                }
                else if (hostNameType == UriHostNameType.Dns)
                {
                    IPHostEntry hostEntry = null;

                    try
                    {
                        hostEntry = Dns.GetHostEntry(proxyServer.Host);
                    }
                    catch(SocketException se)
                    {
                        throw new WebException("host not available", se, WebExceptionStatus.ConnectFailure, null);
                    }

                    int addressListSize = hostEntry.AddressList.Length;
                    for (int i = 0; i < addressListSize; i++)
                    {
                        if ((address = hostEntry.AddressList[i]) != null)
                        {
                            break;
                        }
                    }

                    if (address == null)
                    {
                        throw new WebException("Unable to resolve Dns entry to valid IPv4 Address", WebExceptionStatus.NameResolutionFailure);
                    }
                }
                else
                {
                    throw new WebException("Only IPv4 or Dns host names allowed.");
                }

                // If socket was not found in waiting connections, then we create new one.
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);

                // Connect to remote endpoint
                try
                {
                    IPEndPoint remoteEP = new IPEndPoint(address, proxyServer.Port);
                    socket.Connect((EndPoint)remoteEP);
                }
                catch (SocketException e)
                {
                    throw new WebException("connection failed", e, WebExceptionStatus.ConnectFailure, null);
                }

                bool isHttps = m_originalUrl.Scheme == "https";

                // We have connected socket. Create request stream
                retStream = new InputNetworkStreamWrapper(new NetworkStream(socket), socket, !isHttps, proxyServer.Host + ":" + proxyServer.Port);

                // For https proxy works differenly from http.
                if (isHttps)
                {
                    // If proxy is set, then for https we need to send "CONNECT" command to proxy.
                    // Once this command is send, the socket from proxy works as if it is the socket to the destination server.
                    if (proxyServer != targetServer)
                    {
                        String request = "CONNECT " + remoteServer + " HTTP/" + ProtocolVersion + "\r\n\r\n";
                        Byte[] bytesToSend = Encoding.UTF8.GetBytes(request);
                        retStream.Write(bytesToSend, 0, bytesToSend.Length);

                        // Now proxy should respond with the connected status. If it is successul, then we are good to go.
                        CoreResponseData respData = ParseHTTPResponse(retStream, m_keepAlive);
                        if (respData.m_statusCode != (int)HttpStatusCode.OK)
                        {
                            throw new WebException("Proxy returned " + respData.m_statusCode, WebExceptionStatus.ConnectFailure);
                        }
                    }

                    // Once connection estiblished need to create secure stream and authenticate server.
                    SslStream sslStream = new SslStream(retStream.m_Socket);

                    // Throws exception is fails.
                    sslStream.AuthenticateAsClient(m_originalUrl.Host, null, m_caCerts, m_caCerts != null ? SslVerification.CertificateRequired : SslVerification.NoVerification, SslProtocols.Default);

                    // Changes the stream to SSL stream.
                    retStream.m_Stream = sslStream;

                    // Changes the address. Originally socket was connected to proxy, now as if it connected to m_originalUrl.Host on m_originalUrl.Port
                    retStream.m_rmAddrAndPort = m_originalUrl.Host + ":" + m_originalUrl.Port;
                }

                lock (m_ConnectedStreams)
                {
                    m_ConnectedStreams.Add(retStream);

                    // if the current stream list is empty then start the timer that drops unused connections.
                    if (m_ConnectedStreams.Count == 1)
                    {
                        m_DropOldConnectionsTimer.Change(HttpListener.DefaultKeepAliveMilliseconds, System.Threading.Timeout.Infinite);
                    }
                }
            }

            return retStream;
        }
 /// <summary>
 /// Removes the given stream from the connection pool
 /// </summary>
 internal static void RemoveStreamFromPool(InputNetworkStreamWrapper stream)
 {
     lock (m_ConnectedStreams)
     {
         if (m_ConnectedStreams.Contains(stream))
         {
             m_ConnectedStreams.Remove(stream);
         }
     }
 }
 /// <summary>
 /// Closes the stream attached to this listener context. 
 /// </summary>
 public void Close(int lingerValue)
 {
     try
     {                
         // Close the underlying stream
         if (m_clientOutputStream != null)
         {
             m_clientOutputStream.m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerValue);
             m_clientOutputStream.Dispose();
             m_clientOutputStream = null;
         }
         if (m_clientInputStream != null)
         {
             m_clientInputStream.Dispose();
             m_clientInputStream = null;
         }
     }
     catch
     {
     }
 }
Exemplo n.º 15
0
        /// <summary>
        /// Closes a response stream, if present.
        /// </summary>
        /// <param name="disposing">Not used.</param>
        protected override void Dispose(bool disposing)
        {
            if (m_responseStream != null)
            {
                bool closeConnection = true;
                if (m_httpWebRequest.KeepAlive)
                {
                    string connValue = null;

                    // Check if server have sent use "Connection:Close"
                    if (m_httpResponseHeaders != null) connValue = m_httpResponseHeaders[HttpKnownHeaderNames.Connection];

                    // If server had not send this header or value is not "close", then we keep connection.
                    closeConnection = connValue == null || connValue.ToLower() == HttpKnownHeaderValues.close;

                    // Add new socket and port used to connect to the list of sockets.
                    // Save connected socket and Destination IP End Point, so it can be used next time.
                    // But first we need to validate that this socket is already not in the list. We do not want same socket to be twice in the list.
                    lock (HttpWebRequest.m_ConnectedStreams)
                    {
                        // If it is not in the list - Add it
                        if (closeConnection)
                        {
                            if (HttpWebRequest.m_ConnectedStreams.Contains(m_responseStream))
                            {
                                // Either KeepAlive was not set or server requested closing connection.
                                HttpWebRequest.m_ConnectedStreams.Remove(m_responseStream);
                            }

                            // Closing connection socket.
                            m_responseStream.Dispose();
                        }
                        else
                        {
                            m_responseStream.ReleaseStream();
                        }
                    }

                }
                
                // Set flag that we already completed work on this stream.
                m_responseStream = null;
            }
        }
Exemplo n.º 16
0
 /// <summary>
 /// Sets the response stream.
 /// </summary>
 /// <param name="stream"></param>
 /// <remarks>
 /// Used internally during creation of HttpWebResponse.
 /// </remarks>
 internal void SetResponseStream(InputNetworkStreamWrapper stream)
 {
     m_responseStream = stream;
 }